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
{//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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值