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

转自: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 getset; }
        
/// <summary>
        
/// 获取或设置文件名
        
/// </summary>

        public string FileName getset; }
        
/// <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(falsenullnull);
        }

        
/// <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(
thisnew BlockFinishedEventArgs(BlockIndex));
        }

        
internal virtual void OnConnectLost()
        
{
            
if (!_IsAlive)
                
return;
            Stop();
            
if (ConnectLost != null)
                ConnectLost(
thisnew EventArgs());
        }

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

        public int SendString(string str)
        
{
            
try
            
{
                
return _Socket.EndSend(BeginSendString(str, nullnull));
            }

            
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(
thisnew 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
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值