C#Socket 文件传输,支持断点续传

最近做一个程序需要传送文件,在网上找了好久也没找到好用的方案,于是自己写了一个,与大家分享,希望大家帮忙改进,拍砖欢迎~
文件采取分块发送,每块单独校验,能够保证文件的完整性.同时还提供磁盘缓存功能.
经过实际测试,通过局域网(有线和WiFi)传送一个5G左右的文件取得成功.
最大缺点是CPU占用率过高,测试中发送端(939AMD3000+)达到40%,接收端(双核T9600、939AMD3200+)分别为15%和35%左右.
性能确实还有待改进....
贴出部分代码,其他的放附件里:
复制代码
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Takamachi660.FileTransmissionSolution
{//Version0.6
CRC32算法

一些常量和扩展方法

一些委托

文件区块类

事件参数类

文件区块抽象集合类

#region文件传输基类
publicabstractclassFileTransmission:IDisposable
{
internalFileStream_FileStream;
//internalreadonlyTransmissionMode_Mode;
///<summary>
///总区块数
///</summary>

internalint_TotalBlock;
///<summary>
///最后一个区块的大小
///</summary>

internalint_LastBlockSize;
internalList<int>_FinishedBlock;
internalbyte[]ReceiveBuf;
internalSocket_Socket;
internalEventWaitHandle_WaitHandle;
internalbool_IsAlive;
internalFileBlockCollection_Blocks;
internalDateTime_StartTime;
///<summary>
///上一个区块完成的时间
///</summary>

internalDateTime_PriorBlockTime;
internaldouble_ByteSpeed;
///<summary>
///获取或设置一个值,该值指示是否启用磁盘缓存
///</summary>

publicboolEnabledIOBuffer
{
get{return_Blocks._EnabledIOBuffer;}
set{_Blocks.EnabledIOBuffer=value;}
}

///<summary>
///获取或设置磁盘缓存的大小(单位:区块数)
///</summary>

publicintIOBufferSize
{
get{return_Blocks._IOBufferSize;}
set
{
if(!_Blocks._EnabledIOBuffer)
thrownewInvalidOperationException("IOBufferisnotenabled!");
_Blocks._IOBufferSize
=value;
}

}

///<summary>
///获取当前磁盘缓存中的区块数
///</summary>

publicintCurrentIOBufferSize
{
get
{
if(!_Blocks._EnabledIOBuffer)
return0;
return_Blocks._IOBuffer.Count;
}

}

///<summary>
///获取或设置该传输的目标连接
///</summary>

publicSocketSocket
{
get{return_Socket;}
set
{
try
{
if(value.ProtocolType!=ProtocolType.Tcp)
thrownewArgumentException("SocketProtocolmustbeTCP","Socket");
_Socket
=value;
_Socket.ReceiveBufferSize
=_Socket.SendBufferSize=Consts.NetBlockMaxSize;
}

catch(Exceptionex)
{
OnErrorOccurred(ex);
}

}

}

///<summary>
///获取与此传输关联的文件流
///</summary>

publicFileStreamFileStream{get{return_FileStream;}}
///<summary>
///获取或设置文件路径
///</summary>

publicstringFilePath{get;set;}
///<summary>
///获取或设置文件名
///</summary>

publicstringFileName{get;set;}
///<summary>
///获取或设置文件名(包括路径)
///</summary>

publicstringFullFileName
{
get
{
try
{
returnFilePath.TrimEnd('\\')+"\\"+FileName;
}

catch(Exceptionex)
{
OnErrorOccurred(ex);
returnnull;
}

}

set
{
try
{
inti=value.LastIndexOf('\\');
if(i>0)
FilePath
=value.Substring(0,i);
else
FilePath
=Environment.CurrentDirectory;
FileName
=value.Substring(i+1);
}

catch(Exceptionex)
{
OnErrorOccurred(ex);
}

}

}

///<summary>
///一个区块完成时发生
///</summary>

publiceventBlockFinishedEventHandlerBlockFinished;
///<summary>
///全部完成时发生
///</summary>

publiceventEventHandlerAllFinished;
///<summary>
///连接中断时发生
///</summary>

publiceventEventHandlerConnectLost;
///<summary>
///出现错误时发生
///</summary>

publiceventFileTransmissionErrorOccurEventHandlerErrorOccurred;
///<summary>
///获取一个值,该值指示传输是否正在进行
///</summary>

publicboolIsAlive{get{return_IsAlive;}}
///<summary>
///获取传输开始的时间
///</summary>

publicDateTimeStartTime{get{return_StartTime;}}
///<summary>
///获取已用时
///</summary>

publicTimeSpanTimePast{get{returnDateTime.Now-_StartTime;}}
///<summary>
///获取估计剩余时间
///</summary>

publicabstractTimeSpanTimeRemaining{get;}
///<summary>
///获取平均速率(区块/秒)
///</summary>

publicdoubleBlockAverSpeed
{
get
{
return_FinishedBlock.Count/TimePast.TotalSeconds;
}

}

///<summary>
///获取平均速率(字节/秒)
///</summary>

publicdoubleByteAverSpeed
{
get
{
returnBlockAverSpeed*Consts.BlockSize;
}

}

///<summary>
///获取平均速率(千字节/秒)
///</summary>

publicdoubleKByteAverSpeed
{
get
{
returnByteAverSpeed/1024;
}

}

///<summary>
///获取瞬时速率(字节/秒)
///</summary>

publicdoubleByteSpeed
{
get
{
return_ByteSpeed;
}

}

///<summary>
///获取瞬时速率(千字节/秒)
///</summary>

publicdoubleKByteSpeed
{
get
{
return_ByteSpeed/1024;
}

}

///<summary>
///获取文件总长度
///</summary>

publiclongTotalSize
{
get
{
return(long)(_TotalBlock-1)*(long)Consts.BlockSize+(long)_LastBlockSize;
}

}

///<summary>
///获取已完成的数据长度
///</summary>

publicabstractlongFinishedSize{get;}
///<summary>
///获取进度值(%)
///</summary>

publicdoubleProgress
{
get
{
return((double)FinishedSize/(double)TotalSize)*100;
}

}

///<summary>
///获取该传输的区块集合
///</summary>

publicFileBlockCollectionBlocks{get{return_Blocks;}}
///<summary>
///默认构造函数
///</summary>

publicFileTransmission()
{
_FinishedBlock
=newList<int>();
_WaitHandle
=newEventWaitHandle(false,EventResetMode.ManualReset);
_Blocks
=newFileBlockCollection(this);
}

///<summary>
///构造函数
///</summary>
///<paramname="FilePath">文件路径</param>
///<paramname="FileName">文件名</param>

publicFileTransmission(stringFilePath,stringFileName)
{
_FinishedBlock
=newList<int>();
_WaitHandle
=newEventWaitHandle(true,EventResetMode.ManualReset);
_Blocks
=newFileBlockCollection(this);

this.FilePath=FilePath;
this.FileName=FileName;
}

///<summary>
///初始化接收缓存
///</summary>

internalvoidInitializeReceiveBuf()
{
try
{
ReceiveBuf
=newbyte[_Socket.ReceiveBufferSize];
}

catch(Exceptionex)
{
OnErrorOccurred(ex);
}

}

///<summary>
///开始异步接收
///</summary>

internalabstractIAsyncResultBeginReceive();
///<summary>
///开始传输
///</summary>

publicvirtualvoidStart()
{
try
{
_IsAlive
=true;
_StartTime
=DateTime.Now;
_WaitHandle.Reset();
}

catch(Exceptionex)
{
OnErrorOccurred(ex);
}

}

///<summary>
///中止传输
///</summary>
///<paramname="ShutDownSocket">是否关闭Socket</param>

publicvirtualvoidStop(boolShutDownSocket)
{
try
{
_IsAlive
=false;
_FileStream.Close();
_FileStream
=null;
_WaitHandle.Set();
if(ShutDownSocket)
{
_Socket.Shutdown(SocketShutdown.Both);
_Socket.Close();
}

}

catch(Exceptionex)
{
OnErrorOccurred(ex);
}

}

///<summary>
///异步中止传输,不关闭Socket
///</summary>

internalvoidStop()
{
newDelegate_Void_Bool(Stop).BeginInvoke(false,null,null);
}

///<summary>
///等待传输完成
///</summary>

publicboolWaitForExit()
{
return_WaitHandle.WaitOne();
}

///<summary>
///等待传输完成
///</summary>

publicboolWaitForExit(intmillisecondsTimeout,boolexitContext)
{
return_WaitHandle.WaitOne(millisecondsTimeout,exitContext);
}

///<summary>
///等待传输完成
///</summary>

publicboolWaitForExit(TimeSpantimeout,boolexitContext)
{
return_WaitHandle.WaitOne(timeout,exitContext);
}

internalvirtualvoidOnBlockFinished(intBlockIndex)
{
if(!_FinishedBlock.Exists(a=>a==BlockIndex))
_FinishedBlock.Add(BlockIndex);
if(BlockIndex==_TotalBlock-1)
_ByteSpeed
=_LastBlockSize/(DateTime.Now-_PriorBlockTime).TotalSeconds;
else
_ByteSpeed
=Consts.BlockSize/(DateTime.Now-_PriorBlockTime).TotalSeconds;
_PriorBlockTime
=DateTime.Now;
if(BlockFinished!=null)
BlockFinished(
this,newBlockFinishedEventArgs(BlockIndex));
}

internalvirtualvoidOnConnectLost()
{
if(!_IsAlive)
return;
Stop();
if(ConnectLost!=null)
ConnectLost(
this,newEventArgs());
}

///<summary>
///同步发送字符串
///</summary>

publicintSendString(stringstr)
{
try
{
return_Socket.EndSend(BeginSendString(str,null,null));
}

catch(SocketException)
{
OnConnectLost();
return0;
}

catch(Exceptionex)
{
OnErrorOccurred(ex);
return0;
}

}

///<summary>
///异步发送字符串并使用默认的回调方法
///</summary>

publicvoidSendStringAsync(stringstr)
{
BeginSendString(str,SendCallback,
null);
}

///<summary>
///异步发送字符串并使用指定的的回调方法和参数
///</summary>

publicIAsyncResultBeginSendString(stringstr,AsyncCallbackcallback,objectstate)
{
try
{
if(!_IsAlive)
thrownewInvalidOperationException("IsNotAlive");
byte[]ToSend=str.ToBytes();
return_Socket.BeginSend(ToSend,0,ToSend.Length,SocketFlags.None,callback,state);
}

catch(SocketException)
{
OnConnectLost();
returnnull;
}

catch(Exceptionex)
{
OnErrorOccurred(ex);
returnnull;
}

}

internalvoidSendCallback(IAsyncResultar)
{
try
{
_Socket.EndSend(ar);
}

catch(SocketException)
{
OnConnectLost();
}

catch(Exceptionex)
{
OnErrorOccurred(ex);
}

if(ar.AsyncState!=null)
{
if(ar.AsyncStateisint)
{
OnBlockFinished((
int)ar.AsyncState);
}

}

}

internalvirtualvoidOnAllFinished()
{
if(AllFinished!=null)
AllFinished(
this,newEventArgs());
}

internalvirtualvoidOnErrorOccurred(ExceptioninnerException)
{
FileTransmissionErrorOccurEventArgseventargs
=newFileTransmissionErrorOccurEventArgs(innerException);
if(ErrorOccurred!=null)
ErrorOccurred(
this,eventargs);
if(!eventargs.Continue)
throwinnerException;
}

voidSystem.IDisposable.Dispose()
{
_FileStream.Close();
_Socket.Close();
}

}

#endregion


发送端类

接收端类
}
复制代码

VS2008完整项目文件,包括类库和一个简单的Demo:
/Files/takamachi660/SendFileTest_v0.6.rar

你可能感兴趣的:(socket)