您的位置:首页 > 编程语言 > C#

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

2016-01-15 17:39 513 查看
转自:http://blog.csdn.net/binyao02123202/article/details/7648088

最近做一个程序需要传送文件,在网上找了好久也没找到好用的方案,于是自己写了一个,与大家分享,希望大家帮忙改进,拍砖欢迎~

文件采取分块发送,每块单独校验,能够保证文件的完整性.同时还提供磁盘缓存功能.

经过实际测试,通过局域网(有线和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 文件传输基类


public abstract class FileTransmission : IDisposable


{


internal FileStream _FileStream;


//internal readonly TransmissionMode _Mode;


/// <summary>


/// 总区块数


/// </summary>


internal int _TotalBlock;


/// <summary>


/// 最后一个区块的大小


/// </summary>


internal int _LastBlockSize;


internal List<int> _FinishedBlock;


internal byte[] ReceiveBuf;


internal Socket _Socket;


internal EventWaitHandle _WaitHandle;


internal bool _IsAlive;


internal FileBlockCollection _Blocks;


internal DateTime _StartTime;


/// <summary>


/// 上一个区块完成的时间


/// </summary>


internal DateTime _PriorBlockTime;


internal double _ByteSpeed;


/// <summary>


/// 获取或设置一个值,该值指示是否启用磁盘缓存


/// </summary>


public bool EnabledIOBuffer


{


get { return _Blocks._EnabledIOBuffer; }


set { _Blocks.EnabledIOBuffer = value; }


}


/// <summary>


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


/// </summary>


public int IOBufferSize


{


get { return _Blocks._IOBufferSize; }


set


{


if (!_Blocks._EnabledIOBuffer)


throw new InvalidOperationException("IOBuffer is not enabled!");


_Blocks._IOBufferSize = value;


}


}


/// <summary>


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


/// </summary>


public int CurrentIOBufferSize


{


get


{


if (!_Blocks._EnabledIOBuffer)


return 0;


return _Blocks._IOBuffer.Count;


}


}


/// <summary>


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


/// </summary>


public Socket Socket


{


get { return _Socket; }


set


{


try


{


if (value.ProtocolType != ProtocolType.Tcp)


throw new 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>


public string FilePath { get; set; }


/// <summary>


/// 获取或设置文件名


/// </summary>


public string FileName { get; set; }


/// <summary>


/// 获取或设置文件名(包括路径)


/// </summary>


public string FullFileName


{


get


{


try


{


return FilePath.TrimEnd('\\') + "\\" + FileName;


}


catch (Exception ex)


{


OnErrorOccurred(ex);


return null;


}


}


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>


public event BlockFinishedEventHandler BlockFinished;


/// <summary>


/// 全部完成时发生


/// </summary>


public event EventHandler AllFinished;


/// <summary>


/// 连接中断时发生


/// </summary>


public event EventHandler ConnectLost;


/// <summary>


/// 出现错误时发生


/// </summary>


public event FileTransmissionErrorOccurEventHandler ErrorOccurred;


/// <summary>


/// 获取一个值,该值指示传输是否正在进行


/// </summary>


public bool IsAlive { get { return _IsAlive; } }


/// <summary>


/// 获取传输开始的时间


/// </summary>


public DateTime StartTime { get { return _StartTime; } }


/// <summary>


/// 获取已用时


/// </summary>


public TimeSpan TimePast { get { return DateTime.Now - _StartTime; } }


/// <summary>


/// 获取估计剩余时间


/// </summary>


public abstract TimeSpan TimeRemaining { get; }


/// <summary>


/// 获取平均速率(区块/秒)


/// </summary>


public double BlockAverSpeed


{


get


{


return _FinishedBlock.Count / TimePast.TotalSeconds;


}


}


/// <summary>


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


/// </summary>


public double ByteAverSpeed


{


get


{


return BlockAverSpeed * Consts.BlockSize;


}


}


/// <summary>


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


/// </summary>


public double KByteAverSpeed


{


get


{


return ByteAverSpeed / 1024;


}


}


/// <summary>


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


/// </summary>


public double ByteSpeed


{


get


{


return _ByteSpeed;


}


}


/// <summary>


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


/// </summary>


public double KByteSpeed


{


get


{


return _ByteSpeed / 1024;


}


}


/// <summary>


/// 获取文件总长度


/// </summary>


public long TotalSize


{


get


{


return (long)(_TotalBlock - 1) * (long)Consts.BlockSize + (long)_LastBlockSize;


}


}


/// <summary>


/// 获取已完成的数据长度


/// </summary>


public abstract long FinishedSize { get; }


/// <summary>


/// 获取进度值(%)


/// </summary>


public double 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>


internal void InitializeReceiveBuf()


{


try


{


ReceiveBuf = new byte[_Socket.ReceiveBufferSize];


}


catch (Exception ex)


{


OnErrorOccurred(ex);


}


}


/// <summary>


/// 开始异步接收


/// </summary>


internal abstract IAsyncResult BeginReceive();


/// <summary>


/// 开始传输


/// </summary>


public virtual void Start()


{


try


{


_IsAlive = true;


_StartTime = DateTime.Now;


_WaitHandle.Reset();


}


catch (Exception ex)


{


OnErrorOccurred(ex);


}


}


/// <summary>


/// 中止传输


/// </summary>


/// <param name="ShutDownSocket">是否关闭Socket</param>


public virtual void 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>


internal void Stop()


{


new Delegate_Void_Bool(Stop).BeginInvoke(false, null, null);


}


/// <summary>


/// 等待传输完成


/// </summary>


public bool WaitForExit()


{


return _WaitHandle.WaitOne();


}


/// <summary>


/// 等待传输完成


/// </summary>


public bool WaitForExit(int millisecondsTimeout, bool exitContext)


{


return _WaitHandle.WaitOne(millisecondsTimeout, exitContext);


}


/// <summary>


/// 等待传输完成


/// </summary>


public bool WaitForExit(TimeSpan timeout, bool exitContext)


{


return _WaitHandle.WaitOne(timeout, exitContext);


}


internal virtual void 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));


}


internal virtual void OnConnectLost()


{


if (!_IsAlive)


return;


Stop();


if (ConnectLost != null)


ConnectLost(this, new EventArgs());


}


/// <summary>


/// 同步发送字符串


/// </summary>


public int SendString(string str)


{


try


{


return _Socket.EndSend(BeginSendString(str, null, null));


}


catch (SocketException)


{


OnConnectLost();


return 0;


}


catch (Exception ex)


{


OnErrorOccurred(ex);


return 0;


}


}


/// <summary>


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


/// </summary>


public void SendStringAsync(string str)


{


BeginSendString(str, SendCallback, null);


}


/// <summary>


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


/// </summary>


public IAsyncResult BeginSendString(string str, AsyncCallback callback, object state)


{


try


{


if (!_IsAlive)


throw new InvalidOperationException("Is Not Alive");


byte[] ToSend = str.ToBytes();


return _Socket.BeginSend(ToSend, 0, ToSend.Length, SocketFlags.None, callback, state);


}


catch (SocketException)


{


OnConnectLost();


return null;


}


catch (Exception ex)


{


OnErrorOccurred(ex);


return null;


}


}


internal void SendCallback(IAsyncResult ar)


{


try


{


_Socket.EndSend(ar);


}


catch (SocketException)


{


OnConnectLost();


}


catch (Exception ex)


{


OnErrorOccurred(ex);


}


if (ar.AsyncState != null)


{


if (ar.AsyncState is int)


{


OnBlockFinished((int)ar.AsyncState);


}


}


}


internal virtual void OnAllFinished()


{


if (AllFinished != null)


AllFinished(this, new EventArgs());


}


internal virtual void 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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: