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

来源:互联网 发布:数据恢复网 编辑:程序博客网 时间:2024/05/16 01:03
最近做一个程序需要传送文件,在网上找了好久也没找到好用的方案,于是自己写了一个,与大家分享,希望大家帮忙改进,拍砖欢迎~
文件采取分块发送,每块单独校验,能够保证文件的完整性.同时还提供磁盘缓存功能.
经过实际测试,通过局域网(有线和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
{//Version 0.6
CRC32算法

一些常量和扩展方法

一些委托

文件区块类

事件参数类

文件区块抽象集合类

#region 文件传输基类
publicabstractclass FileTransmission : IDisposable
{
internal FileStream _FileStream;
//internal readonly TransmissionMode _Mode;
///<summary>
/// 总区块数
///</summary>

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

internalint _LastBlockSize;
internal List<int> _FinishedBlock;
internalbyte[] ReceiveBuf;
internal Socket _Socket;
internal EventWaitHandle _WaitHandle;
internalbool _IsAlive;
internal FileBlockCollection _Blocks;
internal DateTime _StartTime;
///<summary>
/// 上一个区块完成的时间
///</summary>

internal DateTime _PriorBlockTime;
internaldouble _ByteSpeed;
///<summary>
/// 获取或设置一个值,该值指示是否启用磁盘缓存
///</summary>

publicbool EnabledIOBuffer
{
get{return _Blocks._EnabledIOBuffer; }
set{ _Blocks.EnabledIOBuffer= value; }
}

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

publicint IOBufferSize
{
get{return _Blocks._IOBufferSize; }
set
{
if (!_Blocks._EnabledIOBuffer)
thrownew InvalidOperationException("IOBuffer is not enabled!");
_Blocks._IOBufferSize
= value;
}

}

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

publicint CurrentIOBufferSize
{
get
{
if (!_Blocks._EnabledIOBuffer)
return0;
return _Blocks._IOBuffer.Count;
}

}

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

public Socket Socket
{
get{return _Socket; }
set
{
try
{
if (value.ProtocolType!= ProtocolType.Tcp)
thrownew ArgumentException("Socket Protocol must be TCP","Socket");
_Socket
= value;
_Socket.ReceiveBufferSize
= _Socket.SendBufferSize= Consts.NetBlockMaxSize;
}

catch (Exception ex)
{
OnErrorOccurred(ex);
}

}

}

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

public FileStream FileStream{get{return _FileStream; } }
///<summary>
/// 获取或设置文件路径
///</summary>

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

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

publicstring FullFileName
{
get
{
try
{
return FilePath.TrimEnd('\\')+"\\"+ FileName;
}

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

}

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

catch (Exception ex)
{
OnErrorOccurred(ex);
}

}

}

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

publicevent BlockFinishedEventHandler BlockFinished;
///<summary>
/// 全部完成时发生
///</summary>

publicevent EventHandler AllFinished;
///<summary>
/// 连接中断时发生
///</summary>

publicevent EventHandler ConnectLost;
///<summary>
/// 出现错误时发生
///</summary>

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

publicbool IsAlive{get{return _IsAlive; } }
///<summary>
/// 获取传输开始的时间
///</summary>

public DateTime StartTime{get{return _StartTime; } }
///<summary>
/// 获取已用时
///</summary>

public TimeSpan TimePast{get{return DateTime.Now- _StartTime; } }
///<summary>
/// 获取估计剩余时间
///</summary>

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

publicdouble BlockAverSpeed
{
get
{
return _FinishedBlock.Count/ TimePast.TotalSeconds;
}

}

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

publicdouble ByteAverSpeed
{
get
{
return BlockAverSpeed* Consts.BlockSize;
}

}

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

publicdouble KByteAverSpeed
{
get
{
return ByteAverSpeed/1024;
}

}

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

publicdouble ByteSpeed
{
get
{
return _ByteSpeed;
}

}

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

publicdouble KByteSpeed
{
get
{
return _ByteSpeed/1024;
}

}

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

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

}

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

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

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

}

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

public FileBlockCollection Blocks{get{return _Blocks; } }
///<summary>
/// 默认构造函数
///</summary>

public FileTransmission()
{
_FinishedBlock
=new List<int>();
_WaitHandle
=new EventWaitHandle(false, EventResetMode.ManualReset);
_Blocks
=new FileBlockCollection(this);
}

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

public FileTransmission(string FilePath,string FileName)
{
_FinishedBlock
=new List<int>();
_WaitHandle
=new EventWaitHandle(true, EventResetMode.ManualReset);
_Blocks
=new FileBlockCollection(this);

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

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

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

catch (Exception ex)
{
OnErrorOccurred(ex);
}

}

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

internalabstract IAsyncResult BeginReceive();
///<summary>
/// 开始传输
///</summary>

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

catch (Exception ex)
{
OnErrorOccurred(ex);
}

}

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

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

}

catch (Exception ex)
{
OnErrorOccurred(ex);
}

}

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

internalvoid Stop()
{
new Delegate_Void_Bool(Stop).BeginInvoke(false,null,null);
}

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

publicbool WaitForExit()
{
return _WaitHandle.WaitOne();
}

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

publicbool WaitForExit(int millisecondsTimeout,bool exitContext)
{
return _WaitHandle.WaitOne(millisecondsTimeout, exitContext);
}

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

publicbool WaitForExit(TimeSpan timeout,bool exitContext)
{
return _WaitHandle.WaitOne(timeout, exitContext);
}

internalvirtualvoid OnBlockFinished(int BlockIndex)
{
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,new BlockFinishedEventArgs(BlockIndex));
}

internalvirtualvoid OnConnectLost()
{
if (!_IsAlive)
return;
Stop();
if (ConnectLost!=null)
ConnectLost(
this,new EventArgs());
}

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

publicint SendString(string str)
{
try
{
return _Socket.EndSend(BeginSendString(str,null,null));
}

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

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

}

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

publicvoid SendStringAsync(string str)
{
BeginSendString(str, SendCallback,
null);
}

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

public IAsyncResult BeginSendString(string str, AsyncCallback callback, object state)
{
try
{
if (!_IsAlive)
thrownew InvalidOperationException("Is Not Alive");
byte[] ToSend= str.ToBytes();
return _Socket.BeginSend(ToSend,0, ToSend.Length, SocketFlags.None, callback, state);
}

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

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

}

internalvoid SendCallback(IAsyncResult ar)
{
try
{
_Socket.EndSend(ar);
}

catch (SocketException)
{
OnConnectLost();
}

catch (Exception ex)
{
OnErrorOccurred(ex);
}

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

}

}

internalvirtualvoid OnAllFinished()
{
if (AllFinished!=null)
AllFinished(
this,new EventArgs());
}

internalvirtualvoid OnErrorOccurred(Exception innerException)
{
FileTransmissionErrorOccurEventArgs eventargs
=new FileTransmissionErrorOccurEventArgs(innerException);
if (ErrorOccurred!=null)
ErrorOccurred(
this, eventargs);
if (!eventargs.Continue)
throw innerException;
}

void System.IDisposable.Dispose()
{
_FileStream.Close();
_Socket.Close();
}

}

#endregion


发送端类

接收端类
}
复制代码

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

原创粉丝点击