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

  1.  
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Net.Sockets;
  7. using System.Text;
  8. using System.Threading;
  9. namespace Takamachi660.FileTransmissionSolution
  10. {//Version 0.6
  11.     #region CRC32算法
  12.     /// <summary>
  13.     /// CRC32快速检测算法
  14.     /// 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ZZJ_4Ever/archive/2009/03/31/4038551.aspx
  15.     /// 有稍作修改
  16.     /// </summary>
  17.     public static class CRC32
  18.     {
  19.         static UInt32[] crcTable = {   
  20.          0x0, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,   
  21.          0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,   
  22.          0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,   
  23.          0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,   
  24.          0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,   
  25.          0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,   
  26.          0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,   
  27.          0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,   
  28.          0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x6b6b51f, 0x9fbfe4a5, 0xe8b8d433,   
  29.          0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x86d3d2d, 0x91646c97, 0xe6635c01,   
  30.          0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,   
  31.          0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,   
  32.          0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,   
  33.          0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,   
  34.          0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,   
  35.          0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,   
  36.          0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x4db2615, 0x73dc1683,   
  37.          0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0xa00ae27, 0x7d079eb1,   
  38.          0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,   
  39.          0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,   
  40.          0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,   
  41.          0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,   
  42.          0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,   
  43.          0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,   
  44.          0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713,   
  45.          0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21,   
  46.          0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,   
  47.          0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,   
  48.          0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,   
  49.          0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,   
  50.          0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,   
  51.          0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,                          
  52.                                    };
  53.         public static int GetCRC32(byte[] bytes)
  54.         {
  55.             int iCount = bytes.Length;
  56.             UInt32 crc = 0xFFFFFFFF;
  57.             for (int i = 0; i < iCount; i++)
  58.             {
  59.                 crc = ((crc >> 8) & 0x00FFFFFF) ^ crcTable[(crc ^ bytes[i]) & 0xFF];
  60.             }
  61.             UInt32 temp = crc ^ 0xFFFFFFFF;
  62.             int t = (int)temp;
  63.             return (t);
  64.         }
  65.     }
  66.     #endregion
  67.  
  68.     #region 一些常量和扩展方法
  69.     /// <summary>
  70.     /// 一些常量和扩展方法
  71.     /// </summary>
  72.     public static class Consts
  73.     {
  74.         /// <summary>
  75.         /// 文件区块数据标头
  76.         /// </summary>
  77.         public const byte FileBlockHeader = 0;
  78.         /// <summary>
  79.         /// 字符串信息标头
  80.         /// </summary>
  81.         public const byte StringHeader = 1;
  82.         /// <summary>
  83.         /// 分块大小1MB
  84.         /// </summary>
  85.         public const int BlockSize = 1048576;
  86.         /// <summary>
  87.         /// 网络上传送的数据包最大大小
  88.         /// </summary>
  89.         public const int NetBlockMaxSize = BlockSize + 9;
  90.         /// <summary>
  91.         /// 默认磁盘缓存大小(单位:区块数)
  92.         /// </summary>
  93.         public const int DefaultIOBufferSize = 8;
  94.         /// <summary>
  95.         /// 空格
  96.         /// </summary>
  97.         public const string Space = " ";
  98.         /// <summary>
  99.         /// 空格替代符
  100.         /// </summary>
  101.         public const string SpaceReplacement = @"<SPACE>";
  102.         /// <summary>
  103.         /// 获取校验值
  104.         /// </summary>
  105.         /// <param name="bytes">输入数据</param>
  106.         /// <returns>输出的校验值</returns>
  107.         public static byte[] GetHash(this byte[] bytes)
  108.         {
  109.             return BitConverter.GetBytes(CRC32.GetCRC32(bytes));
  110.         }
  111.         /// <summary>
  112.         /// 比较两二进制数据内容是否完全相同(用于校验值的比较)
  113.         /// </summary>
  114.         /// <param name="THIS">数据一</param>
  115.         /// <param name="obj">数据二</param>
  116.         public static bool BytesEqual(this byte[] THIS, byte[] obj)
  117.         {
  118.             if (THIS.Length != obj.Length)
  119.                 return false;
  120.             for (int index = 0; index < obj.Length; index++)
  121.             {
  122.                 if (THIS[index] != obj[index])
  123.                     return false;
  124.             }
  125.             return true;
  126.         }
  127.         /// <summary>
  128.         /// 将指令字符串转化为二进制数据并添加标头
  129.         /// </summary>
  130.         public static byte[] ToBytes(this string str_input)
  131.         {
  132.             byte[] strdata = Encoding.UTF8.GetBytes(str_input);
  133.             byte[] output = new byte[1 + strdata.Length];
  134.             output[0] = StringHeader;
  135.             System.Array.Copy(strdata, 0, output, 1, strdata.Length);
  136.             return output;
  137.         }
  138.         /// <summary>
  139.         /// 将二进制数据转化为指令字符串
  140.         /// </summary>
  141.         public static string ToFTString(this byte[] bytes_input)
  142.         {
  143.             if (bytes_input[0] != StringHeader)
  144.                 throw new FormatException("Bad Header!");
  145.             return Encoding.UTF8.GetString(bytes_input, 1, bytes_input.Length - 1).TrimEnd('\0');
  146.         }
  147.         /// <summary>
  148.         /// 替换可能会对命令解析造成干扰的字符
  149.         /// </summary>
  150.         public static string DoReplace(this string str_input)
  151.         {
  152.             return str_input.Replace(Space, SpaceReplacement);
  153.         }
  154.         /// <summary>
  155.         /// 还原被替换的字符
  156.         /// </summary>
  157.         public static string DeReplace(this string str_input)
  158.         {
  159.             return str_input.Replace(SpaceReplacement, Space);
  160.         }
  161.     }
  162.     #endregion
  163.  
  164.     #region 一些委托
  165.     public delegate void BlockFinishedEventHandler(object sender, BlockFinishedEventArgs e);
  166.     public delegate void CommandReceivedEventHandler(object sender, CommandReceivedEventArgs e);
  167.     public delegate void FileTransmissionErrorOccurEventHandler(object sender,FileTransmissionErrorOccurEventArgs e);
  168.     public delegate void Delegate_SendBlocks(int Start, int End);
  169.     public delegate void Delegate_Void_Bool(bool logic);
  170.     public delegate int Delegate_Int_Int(int value);
  171.     #endregion
  172.  
  173.     #region 文件区块类
  174.     public class FileBlockException : Exception
  175.     {
  176.         public enum ErrorCode
  177.         {
  178.             BadHeader,
  179.             BadIndex,
  180.             IllegalFileBlockSize,
  181.             ChecksumError,
  182.         }
  183.         public ErrorCode Code { get; set; }
  184.         public FileBlockException(string message, ErrorCode ErrorCode)
  185.             : base(message)
  186.         {
  187.             Code = ErrorCode;
  188.         }
  189.     }
  190.     /// <summary>
  191.     /// 文件区块类
  192.     /// </summary>
  193.     public class FileBlock : IComparable<FileBlock>
  194.     {
  195.         /// <summary>
  196.         /// 与该区块关联的传输对象
  197.         /// </summary>
  198.         internal FileTransmission _Task;
  199.         /// <summary>
  200.         /// 与该区块关联的FileStream
  201.         /// </summary>
  202.         internal FileStream _FileStream;
  203.         /// <summary>
  204.         /// 文件数据
  205.         /// </summary>
  206.         internal byte[] _Data;
  207.         /// <summary>
  208.         /// 数据长度
  209.         /// </summary>
  210.         internal int _DataLength;
  211.         /// <summary>
  212.         /// 数据的Hash值
  213.         /// </summary>
  214.         internal byte[] _DataHash;
  215.         /// <summary>
  216.         /// 获取或设置该区块的序号(该区块在文件中的位置)
  217.         /// </summary>
  218.         public int Index { get; set; }
  219.         /// <summary>
  220.         /// 获取该区块的数据长度
  221.         /// </summary>
  222.         public int DataLength { get { return _DataLength; } }
  223.         /// <summary>
  224.         /// 获取该数据块的校验值
  225.         /// </summary>
  226.         public byte[] DataHash { get { return _DataHash; } }
  227.         /// <summary>
  228.         /// 构造函数
  229.         /// 用于从文件读入区块
  230.         /// </summary>
  231.         /// <param name="fStream">输入的文件流</param>
  232.         /// <param name="BlockIndex">分块位置</param>
  233.         /// <param name="ReadOnCreated">是否立即从文件读取数据</param>
  234.         public FileBlock(FileTransmission TransmissionTask, int BlockIndex, bool ReadOnCreated)
  235.         {
  236.             _Task = TransmissionTask;
  237.             _FileStream = _Task.FileStream;
  238.             Index = BlockIndex;
  239.             if (ReadOnCreated)
  240.                 this.Read(true);
  241.         }
  242.         /// <summary>
  243.         /// 构造函数
  244.         /// 用于从二进制数据读入区块
  245.         /// </summary>
  246.         /// <param name="fStream">要保存的文件流</param>
  247.         /// <param name="ReceivedData">输入的二进制数据</param>
  248.         public FileBlock(FileTransmission TransmissionTask, byte[] ReceivedData)
  249.         {
  250.             _Task = TransmissionTask;
  251.             _FileStream = _Task.FileStream;
  252.             if (ReceivedData[0] != Consts.FileBlockHeader)
  253.                 throw new FileBlockException("Bad Header!", FileBlockException.ErrorCode.BadHeader);
  254.             Index = BitConverter.ToInt32(ReceivedData, 1);
  255.             _DataLength = ReceivedData.Length - 9;
  256.             if (_DataLength > Consts.BlockSize)
  257.                 throw new FileBlockException("Illegal FileBlock Size!", FileBlockException.ErrorCode.IllegalFileBlockSize);
  258.             _Data = new byte[_DataLength];
  259.             _DataHash = new byte[4];
  260.             System.Array.Copy(ReceivedData, 5, _DataHash, 0, 4);
  261.             System.Array.Copy(ReceivedData, 9, _Data, 0, _DataLength);
  262.             if (!_DataHash.BytesEqual(_Data.GetHash()))
  263.                 throw new FileBlockException("Error Hash!", FileBlockException.ErrorCode.ChecksumError);
  264.         }
  265.         /// <summary>
  266.         /// 从文件读入
  267.         /// </summary>
  268.         /// <param name="CalcHashAfterRead">是否在读取后立即计算校验值</param>
  269.         /// <returns>读取块的大小</returns>
  270.         public int Read(bool CalcHashAfterRead)
  271.         {
  272.             _Data = new byte[Consts.BlockSize];
  273.             lock (_FileStream)
  274.             {
  275.                 _FileStream.Position = (long)Index * (long)Consts.BlockSize;
  276.                 _DataLength = _FileStream.Read(_Data, 0, Consts.BlockSize);
  277.             }
  278.             if (_Data.Length != _DataLength)
  279.             {
  280.                 byte[] old = _Data;
  281.                 _Data = new byte[_DataLength];
  282.                 System.Array.Copy(old, _Data, _DataLength);
  283.             }
  284.             if (CalcHashAfterRead)
  285.                 CalcHash();
  286.             return _DataLength;
  287.         }
  288.         /// <summary>
  289.         /// 计算校验值
  290.         /// </summary>
  291.         /// <returns>校验值</returns>
  292.         public byte[] CalcHash()
  293.         {
  294.             return _DataHash = _Data.GetHash();
  295.         }
  296.         /// <summary>
  297.         /// 将该区块写入文件
  298.         /// </summary>
  299.         public void Write()
  300.         {
  301.             lock (_FileStream)
  302.             {
  303.                 _FileStream.Position = (long)Index * (long)Consts.BlockSize;
  304.                 _FileStream.Write(_Data, 0, _DataLength);
  305.             }
  306.         }
  307.         /// <summary>
  308.         /// 转化为二进制数据以传输
  309.         /// </summary>
  310.         /// <returns></returns>
  311.         public byte[] GetBytes()
  312.         {
  313.             MemoryStream mStream = new MemoryStream(1 + 4 + 4 + _DataLength);
  314.             byte[] Header = new byte[1] { Consts.FileBlockHeader };
  315.             mStream.Write(Header, 0, 1);
  316.             mStream.Write(BitConverter.GetBytes(Index), 0, 4);
  317.             mStream.Write(_DataHash, 0, 4);
  318.             mStream.Write(_Data, 0, _DataLength);
  319.             return mStream.ToArray();
  320.         }
  321.         int System.IComparable<FileBlock>.CompareTo(FileBlock obj)
  322.         {
  323.             return (Index as IComparable<int>).CompareTo(obj.Index);
  324.         }
  325.     }
  326.     #endregion
  327.  
  328.     #region 事件参数类
  329.     public class BlockFinishedEventArgs : EventArgs
  330.     {
  331.         public int BlockIndex { get; set; }
  332.         public BlockFinishedEventArgs(int BlockIndex) { this.BlockIndex = BlockIndex; }
  333.     }
  334.     public class CommandReceivedEventArgs : EventArgs
  335.     {
  336.         public string CommandLine { get; set; }
  337.         public CommandReceivedEventArgs(string CommandLine) { this.CommandLine = CommandLine; }
  338.     }
  339.     public class FileTransmissionErrorOccurEventArgs : EventArgs
  340.     {
  341.         public Exception InnerException { get; set; }
  342.         /// <summary>
  343.         /// 指示是否继续运行
  344.         /// </summary>
  345.         public bool Continue { get; set; }
  346.         public FileTransmissionErrorOccurEventArgs(Exception innerException)
  347.         {
  348.             InnerException = innerException;
  349.             Continue = false;
  350.         }
  351.     }
  352.     #endregion
  353.  
  354.     #region 文件区块抽象集合类
  355.     /// <summary>
  356.     /// 文件区块的抽象集合
  357.     /// 之所以说抽象是因为该集合并不存储实际的区块(缓存区除外)
  358.     /// 而是通过一个索引器来读写文件
  359.     /// 并提供磁盘缓存
  360.     /// </summary>
  361.     public class FileBlockCollection
  362.     {
  363.         /// <summary>
  364.         /// 与该区块关联的传输对象
  365.         /// </summary>
  366.         internal FileTransmission _Task;
  367.         /// <summary>
  368.         /// 与该区块关联的FileStream
  369.         /// </summary>
  370.         internal FileStream _FileStream;
  371.         internal bool _EnabledIOBuffer;
  372.         /// <summary>
  373.         /// 磁盘缓存区
  374.         /// </summary>
  375.         internal Dictionary<int, FileBlock> _IOBuffer;
  376.  
  377.         public FileBlockCollection(FileTransmission TransmissionTask)
  378.         {
  379.             _Task = TransmissionTask;
  380.             _FileStream = _Task.FileStream;
  381.             _IOBufferSize = Consts.DefaultIOBufferSize;
  382.         }
  383.         /// <summary>
  384.         /// 获取或设置一个值,该值指示是否启用磁盘缓存
  385.         /// </summary>
  386.         internal bool EnabledIOBuffer
  387.         {
  388.             get { return _EnabledIOBuffer; }
  389.             set
  390.             {
  391.                 _EnabledIOBuffer = value;
  392.                 if (value)
  393.                     _IOBuffer = new Dictionary<int, FileBlock>();
  394.                 else
  395.                 {
  396.                     if (_Task is FileReceiver)
  397.                         WriteAllBlock();
  398.                     _IOBuffer = null;
  399.                 }
  400.             }
  401.         }
  402.         internal int _IOBufferSize;
  403.         /// <summary>
  404.         /// 获取已接收或已发送的区块序号列表
  405.         /// </summary>
  406.         public List<int> Finished { get { return _Task._FinishedBlock; } }
  407.         /// <summary>
  408.         /// 获取已存在(Hash成功)的区块序号列表
  409.         /// </summary>
  410.         public List<int> Exist
  411.         {
  412.             get
  413.             {
  414.                 if (_Task is FileReceiver)
  415.                     return ((FileReceiver)_Task)._ExistBlock;
  416.                 else
  417.                     return null;
  418.             }
  419.         }
  420.         /// <summary>
  421.         /// 获取被丢弃的区块序号列表
  422.         /// </summary>
  423.         public List<int> Cast
  424.         {
  425.             get
  426.             {
  427.                 if (_Task is FileReceiver)
  428.                     return ((FileReceiver)_Task)._CastBlock;
  429.                 else
  430.                     return null;
  431.             }
  432.         }
  433.         /// <summary>
  434.         /// 获取总区块数
  435.         /// </summary>
  436.         public int Count { get { return _Task._TotalBlock; } }
  437.         /// <summary>
  438.         /// 获取有效区块数(已存在+已接收)
  439.         /// </summary>
  440.         public int CountValid
  441.         {
  442.             get
  443.             {
  444.                 if (_Task is FileReceiver)
  445.                     return _Task._FinishedBlock.Count + ((FileReceiver)_Task)._ExistBlock.Count;
  446.                 else
  447.                     return _Task._FinishedBlock.Count;
  448.  
  449.             }
  450.         }
  451.         /// <summary>
  452.         /// 将缓存中的区块全部写入磁盘
  453.         /// </summary>
  454.         /// <returns>写入的区块数量</returns>
  455.         public int WriteAllBlock()
  456.         {
  457.             if (!_EnabledIOBuffer)
  458.                 return -1;
  459.             int count = 0;
  460.             lock (_IOBuffer)
  461.             {
  462.                 foreach (var b in _IOBuffer)
  463.                 {
  464.                     b.Value.Write();
  465.                     count++;
  466.                 }
  467.                 if (count != _IOBuffer.Count)
  468.                     throw new IOException("Can not Write All FileBlocks!");
  469.                 _IOBuffer.Clear();
  470.             }
  471.             return count;
  472.         }
  473.         /// <summary>
  474.         /// 读取数据以填充缓存
  475.         /// </summary>
  476.         /// <param name="StartIndex">起始区块</param>
  477.         /// <returns>读取的区块数量</returns>
  478.         public int FillIOBuffer(int StartIndex)
  479.         {
  480.             int Index;
  481.             lock (_IOBuffer)
  482.             {
  483.                 _IOBuffer.Clear();
  484.                 for (Index = StartIndex; _IOBuffer.Count < _IOBufferSize && Index < _Task.Blocks.Count; Index++)
  485.                 {
  486.                     _IOBuffer.Add(Index, new FileBlock(_Task, Index, true));
  487.                 }
  488.             }
  489.             return Index - StartIndex;
  490.         }
  491.         /// <summary>
  492.         /// 异步填充缓存
  493.         /// </summary>
  494.         /// <param name="StartIndex">起始区块</param>
  495.         public IAsyncResult BeginFillIOBuffer(int StartIndex,AsyncCallback callback,object state)
  496.         {
  497.             return new Delegate_Int_Int(FillIOBuffer).BeginInvoke(StartIndex, callback, state);
  498.         }
  499.         /// <summary>
  500.         /// 写入区块
  501.         /// </summary>
  502.         /// <param name="value">区块对象</param>
  503.         public void Write(FileBlock value)
  504.         {
  505.             if (_EnabledIOBuffer)
  506.             {
  507.                 if (_IOBuffer.Count >= _IOBufferSize)
  508.                     WriteAllBlock();
  509.                 lock (_IOBuffer)
  510.                     _IOBuffer.Add(value.Index, value);
  511.             }
  512.             else
  513.                 value.Write();
  514.         }
  515.         /// <summary>
  516.         /// 读取或写入区块
  517.         /// </summary>
  518.         /// <param name="BlockIndex">区块序号</param>
  519.         public FileBlock this[int BlockIndex]
  520.         {
  521.             get
  522.             {
  523.                 FileBlock output;
  524.                 if (_EnabledIOBuffer)
  525.                 {
  526.                     
  527.                     bool IsInBuf;
  528.                     lock (_IOBuffer)
  529.                         IsInBuf = _IOBuffer.TryGetValue(BlockIndex, out output);
  530.                     if (IsInBuf)
  531.                         return output;
  532.                     else
  533.                     {
  534.                         output = new FileBlock(_Task, BlockIndex, true);
  535.                         BeginFillIOBuffer(BlockIndex + 1, null, null);
  536.                     }
  537.                 }
  538.                 else
  539.                     output = new FileBlock(_Task, BlockIndex, true);
  540.                 return output;
  541.             }
  542.             set
  543.             {
  544.                 if (BlockIndex != value.Index)
  545.                     throw new FileBlockException("Bad Index!", FileBlockException.ErrorCode.BadIndex);
  546.                 Write(value);
  547.             }
  548.         }
  549.     }
  550.     #endregion
  551.  
  552.     #region 文件传输基类
  553.     public abstract class FileTransmission : IDisposable
  554.     {
  555.         internal FileStream _FileStream;
  556.         //internal readonly TransmissionMode _Mode;
  557.         /// <summary>
  558.         /// 总区块数
  559.         /// </summary>
  560.         internal int _TotalBlock;
  561.         /// <summary>
  562.         /// 最后一个区块的大小
  563.         /// </summary>
  564.         internal int _LastBlockSize;
  565.         internal List<int> _FinishedBlock;
  566.         internal byte[] ReceiveBuf;
  567.         internal Socket _Socket;
  568.         internal EventWaitHandle _WaitHandle;
  569.         internal bool _IsAlive;
  570.         internal FileBlockCollection _Blocks;
  571.         internal DateTime _StartTime;
  572.         /// <summary>
  573.         /// 上一个区块完成的时间
  574.         /// </summary>
  575.         internal DateTime _PriorBlockTime;
  576.         internal double _ByteSpeed;
  577.         /// <summary>
  578.         /// 获取或设置一个值,该值指示是否启用磁盘缓存
  579.         /// </summary>
  580.         public bool EnabledIOBuffer
  581.         {
  582.             get { return _Blocks._EnabledIOBuffer; }
  583.             set { _Blocks.EnabledIOBuffer = value; }
  584.         }
  585.         /// <summary>
  586.         /// 获取或设置磁盘缓存的大小(单位:区块数)
  587.         /// </summary>
  588.         public int IOBufferSize
  589.         {
  590.             get { return _Blocks._IOBufferSize; }
  591.             set
  592.             {
  593.                 if (!_Blocks._EnabledIOBuffer)
  594.                     throw new InvalidOperationException("IOBuffer is not enabled!");
  595.                 _Blocks._IOBufferSize = value;
  596.             }
  597.         }
  598.         /// <summary>
  599.         /// 获取当前磁盘缓存中的区块数
  600.         /// </summary>
  601.         public int CurrentIOBufferSize
  602.         {
  603.             get
  604.             {
  605.                 if (!_Blocks._EnabledIOBuffer)
  606.                     return 0;
  607.                 return _Blocks._IOBuffer.Count;
  608.             }
  609.         }
  610.         /// <summary>
  611.         /// 获取或设置该传输的目标连接
  612.         /// </summary>
  613.         public Socket Socket
  614.         {
  615.             get { return _Socket; }
  616.             set
  617.             {
  618.                 try
  619.                 {
  620.                     if (value.ProtocolType != ProtocolType.Tcp)
  621.                         throw new ArgumentException("Socket Protocol must be TCP", "Socket");
  622.                     _Socket = value;
  623.                     _Socket.ReceiveBufferSize = _Socket.SendBufferSize = Consts.NetBlockMaxSize;
  624.                 }
  625.                 catch (Exception ex)
  626.                 {
  627.                     OnErrorOccurred(ex);
  628.                 }
  629.             }
  630.         }
  631.         /// <summary>
  632.         /// 获取与此传输关联的文件流
  633.         /// </summary>
  634.         public FileStream FileStream { get { return _FileStream; } }
  635.         /// <summary>
  636.         /// 获取或设置文件路径
  637.         /// </summary>
  638.         public string FilePath { get; set; }
  639.         /// <summary>
  640.         /// 获取或设置文件名
  641.         /// </summary>
  642.         public string FileName { get; set; }
  643.         /// <summary>
  644.         /// 获取或设置文件名(包括路径)
  645.         /// </summary>
  646.         public string FullFileName
  647.         {
  648.             get
  649.             {
  650.                 try
  651.                 {
  652.                     return FilePath.TrimEnd('\\') + "\\" + FileName;
  653.                 }
  654.                 catch (Exception ex)
  655.                 {
  656.                     OnErrorOccurred(ex);
  657.                     return null;
  658.                 }
  659.             }
  660.             set
  661.             {
  662.                 try
  663.                 {
  664.                     int i = value.LastIndexOf('\\');
  665.                     if (> 0)
  666.                         FilePath = value.Substring(0, i);
  667.                     else
  668.                         FilePath = Environment.CurrentDirectory;
  669.                     FileName = value.Substring(+ 1);
  670.                 }
  671.                 catch (Exception ex)
  672.                 {
  673.                     OnErrorOccurred(ex);
  674.                 }
  675.             }
  676.         }
  677.         /// <summary>
  678.         /// 一个区块完成时发生
  679.         /// </summary>
  680.         public event BlockFinishedEventHandler BlockFinished;
  681.         /// <summary>
  682.         /// 全部完成时发生
  683.         /// </summary>
  684.         public event EventHandler AllFinished;
  685.         /// <summary>
  686.         /// 连接中断时发生
  687.         /// </summary>
  688.         public event EventHandler ConnectLost;
  689.         /// <summary>
  690.         /// 出现错误时发生
  691.         /// </summary>
  692.         public event FileTransmissionErrorOccurEventHandler ErrorOccurred;
  693.         /// <summary>
  694.         /// 获取一个值,该值指示传输是否正在进行
  695.         /// </summary>
  696.         public bool IsAlive { get { return _IsAlive; } }
  697.         /// <summary>
  698.         /// 获取传输开始的时间
  699.         /// </summary>
  700.         public DateTime StartTime { get { return _StartTime; } }
  701.         /// <summary>
  702.         /// 获取已用时
  703.         /// </summary>
  704.         public TimeSpan TimePast { get { return DateTime.Now - _StartTime; } }
  705.         /// <summary>
  706.         /// 获取估计剩余时间
  707.         /// </summary>
  708.         public abstract TimeSpan TimeRemaining { get; }
  709.         /// <summary>
  710.         /// 获取平均速率(区块/秒)
  711.         /// </summary>
  712.         public double BlockAverSpeed
  713.         {
  714.             get
  715.             {
  716.                 return _FinishedBlock.Count / TimePast.TotalSeconds;
  717.             }
  718.         }
  719.         /// <summary>
  720.         /// 获取平均速率(字节/秒)
  721.         /// </summary>
  722.         public double ByteAverSpeed
  723.         {
  724.             get
  725.             {
  726.                 return BlockAverSpeed * Consts.BlockSize;
  727.             }
  728.         }
  729.         /// <summary>
  730.         /// 获取平均速率(千字节/秒)
  731.         /// </summary>
  732.         public double KByteAverSpeed
  733.         {
  734.             get
  735.             {
  736.                 return ByteAverSpeed / 1024;
  737.             }
  738.         }
  739.         /// <summary>
  740.         /// 获取瞬时速率(字节/秒)
  741.         /// </summary>
  742.         public double ByteSpeed
  743.         {
  744.             get
  745.             {
  746.                 return _ByteSpeed;
  747.             }
  748.         }
  749.         /// <summary>
  750.         /// 获取瞬时速率(千字节/秒)
  751.         /// </summary>
  752.         public double KByteSpeed
  753.         {
  754.             get
  755.             {
  756.                 return _ByteSpeed / 1024;
  757.             }
  758.         }
  759.         /// <summary>
  760.         /// 获取文件总长度
  761.         /// </summary>
  762.         public long TotalSize
  763.         {
  764.             get
  765.             {
  766.                 return (long)(_TotalBlock - 1) * (long)Consts.BlockSize + (long)_LastBlockSize;
  767.             }
  768.         }
  769.         /// <summary>
  770.         /// 获取已完成的数据长度
  771.         /// </summary>
  772.         public abstract long FinishedSize { get; }
  773.         /// <summary>
  774.         /// 获取进度值(%)
  775.         /// </summary>
  776.         public double Progress
  777.         {
  778.             get
  779.             {
  780.                 return ((double)FinishedSize / (double)TotalSize) * 100;
  781.             }
  782.         }
  783.         /// <summary>
  784.         /// 获取该传输的区块集合
  785.         /// </summary>
  786.         public FileBlockCollection Blocks { get { return _Blocks; } }
  787.         /// <summary>
  788.         /// 默认构造函数
  789.         /// </summary>
  790.         public FileTransmission()
  791.         {
  792.             _FinishedBlock = new List<int>();
  793.             _WaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
  794.             _Blocks = new FileBlockCollection(this);
  795.         }
  796.         /// <summary>
  797.         /// 构造函数
  798.         /// </summary>
  799.         /// <param name="FilePath">文件路径</param>
  800.         /// <param name="FileName">文件名</param>
  801.         public FileTransmission(string FilePath, string FileName)
  802.         {
  803.             _FinishedBlock = new List<int>();
  804.             _WaitHandle = new EventWaitHandle(true, EventResetMode.ManualReset);
  805.             _Blocks = new FileBlockCollection(this);
  806.  
  807.             this.FilePath = FilePath;
  808.             this.FileName = FileName;
  809.         }
  810.         /// <summary>
  811.         /// 初始化接收缓存
  812.         /// </summary>
  813.         internal void InitializeReceiveBuf()
  814.         {
  815.             try
  816.             {
  817.                 ReceiveBuf = new byte[_Socket.ReceiveBufferSize];
  818.             }
  819.             catch (Exception ex)
  820.             {
  821.                 OnErrorOccurred(ex);
  822.             }
  823.         }
  824.         /// <summary>
  825.         /// 开始异步接收
  826.         /// </summary>
  827.         internal abstract IAsyncResult BeginReceive();
  828.         /// <summary>
  829.         /// 开始传输
  830.         /// </summary>
  831.         public virtual void Start()
  832.         {
  833.             try
  834.             {
  835.                 _IsAlive = true;
  836.                 _StartTime = DateTime.Now;
  837.                 _WaitHandle.Reset();
  838.             }
  839.             catch (Exception ex)
  840.             {
  841.                 OnErrorOccurred(ex);
  842.             }
  843.         }
  844.         /// <summary>
  845.         /// 中止传输
  846.         /// </summary>
  847.         /// <param name="ShutDownSocket">是否关闭Socket</param>
  848.         public virtual void Stop(bool ShutDownSocket)
  849.         {
  850.             try
  851.             {
  852.                 _IsAlive = false;
  853.                 _FileStream.Close();
  854.                 _FileStream = null;
  855.                 _WaitHandle.Set();
  856.                 if (ShutDownSocket)
  857.                 {
  858.                     _Socket.Shutdown(SocketShutdown.Both);
  859.                     _Socket.Close();
  860.                 }
  861.             }
  862.             catch (Exception ex)
  863.             {
  864.                 OnErrorOccurred(ex);
  865.             }
  866.         }
  867.         /// <summary>
  868.         /// 异步中止传输,不关闭Socket
  869.         /// </summary>
  870.         internal void Stop()
  871.         {
  872.             new Delegate_Void_Bool(Stop).BeginInvoke(false, null, null);
  873.         }
  874.         /// <summary>
  875.         /// 等待传输完成
  876.         /// </summary>
  877.         public bool WaitForExit()
  878.         {
  879.             return _WaitHandle.WaitOne();
  880.         }
  881.         /// <summary>
  882.         /// 等待传输完成
  883.         /// </summary>
  884.         public bool WaitForExit(int millisecondsTimeout, bool exitContext)
  885.         {
  886.             return _WaitHandle.WaitOne(millisecondsTimeout, exitContext);
  887.         }
  888.         /// <summary>
  889.         /// 等待传输完成
  890.         /// </summary>
  891.         public bool WaitForExit(TimeSpan timeout, bool exitContext)
  892.         {
  893.             return _WaitHandle.WaitOne(timeout, exitContext);
  894.         }
  895.         internal virtual void OnBlockFinished(int BlockIndex)
  896.         {
  897.             if (!_FinishedBlock.Exists(=> a == BlockIndex))
  898.                 _FinishedBlock.Add(BlockIndex);
  899.             if (BlockIndex == _TotalBlock - 1)
  900.                 _ByteSpeed = _LastBlockSize / (DateTime.Now - _PriorBlockTime).TotalSeconds;
  901.             else
  902.                 _ByteSpeed = Consts.BlockSize / (DateTime.Now - _PriorBlockTime).TotalSeconds;
  903.             _PriorBlockTime = DateTime.Now;
  904.             if (BlockFinished != null)
  905.                 BlockFinished(this, new BlockFinishedEventArgs(BlockIndex));
  906.         }
  907.         internal virtual void OnConnectLost()
  908.         {
  909.             if (!_IsAlive)
  910.                 return;
  911.             Stop();
  912.             if (ConnectLost != null)
  913.                 ConnectLost(this, new EventArgs());
  914.         }
  915.         /// <summary>
  916.         /// 同步发送字符串
  917.         /// </summary>
  918.         public int SendString(string str)
  919.         {
  920.             try
  921.             {
  922.                 return _Socket.EndSend(BeginSendString(str, null, null));
  923.             }
  924.             catch (SocketException)
  925.             {
  926.                 OnConnectLost();
  927.                 return 0;
  928.             }
  929.             catch (Exception ex)
  930.             {
  931.                 OnErrorOccurred(ex);
  932.                 return 0;
  933.             }
  934.         }
  935.         /// <summary>
  936.         /// 异步发送字符串并使用默认的回调方法
  937.         /// </summary>
  938.         public void SendStringAsync(string str)
  939.         {
  940.             BeginSendString(str, SendCallback, null);
  941.         }
  942.         /// <summary>
  943.         /// 异步发送字符串并使用指定的的回调方法和参数
  944.         /// </summary>
  945.         public IAsyncResult BeginSendString(string str, AsyncCallback callback, object state)
  946.         {
  947.             try
  948.             {
  949.                 if (!_IsAlive)
  950.                     throw new InvalidOperationException("Is Not Alive");
  951.                 byte[] ToSend = str.ToBytes();
  952.                 return _Socket.BeginSend(ToSend, 0, ToSend.Length, SocketFlags.None, callback, state);
  953.             }
  954.             catch (SocketException)
  955.             {
  956.                 OnConnectLost();
  957.                 return null;
  958.             }
  959.             catch (Exception ex)
  960.             {
  961.                 OnErrorOccurred(ex);
  962.                 return null;
  963.             }
  964.         }
  965.         internal void SendCallback(IAsyncResult ar)
  966.         {
  967.             try
  968.             {
  969.                 _Socket.EndSend(ar);
  970.             }
  971.             catch (SocketException)
  972.             {
  973.                 OnConnectLost();
  974.             }
  975.             catch (Exception ex)
  976.             {
  977.                 OnErrorOccurred(ex);
  978.             }
  979.             if (ar.AsyncState != null)
  980.             {
  981.                 if (ar.AsyncState is int)
  982.                 {
  983.                     OnBlockFinished((int)ar.AsyncState);
  984.                 }
  985.             }
  986.         }
  987.         internal virtual void OnAllFinished()
  988.         {
  989.             if (AllFinished != null)
  990.                 AllFinished(this, new EventArgs());
  991.         }
  992.         internal virtual void OnErrorOccurred(Exception innerException)
  993.         {
  994.             FileTransmissionErrorOccurEventArgs eventargs = new FileTransmissionErrorOccurEventArgs(innerException);
  995.             if (ErrorOccurred != null)
  996.                 ErrorOccurred(this, eventargs);
  997.             if (!eventargs.Continue)
  998.                 throw innerException;
  999.         }
  1000.         void System.IDisposable.Dispose()
  1001.         {
  1002.             _FileStream.Close();
  1003.             _Socket.Close();
  1004.         }
  1005.     }
  1006.     #endregion
  1007.  
  1008.     #region 发送端类
  1009.     /// <summary>
  1010.     /// 发送端
  1011.     /// 传输前发送端创建该类实例
  1012.     /// 设置必要属性后
  1013.     /// 调用Start()方法开始传输
  1014.     /// </summary>
  1015.     public class FileSender : FileTransmission
  1016.     {
  1017.         /// <summary>
  1018.         /// 接收到命令时发生
  1019.         /// </summary>
  1020.         public event CommandReceivedEventHandler CommandReceived;
  1021.         /// <summary>
  1022.         /// 开始异步接收
  1023.         /// </summary>
  1024.         internal override IAsyncResult BeginReceive()
  1025.         {
  1026.             InitializeReceiveBuf();
  1027.             try
  1028.             {
  1029.                 return _Socket.BeginReceive(ReceiveBuf, 0, ReceiveBuf.Length, SocketFlags.None, ReceiveCallback, null);
  1030.             }
  1031.             catch (SocketException)
  1032.             {
  1033.                 OnConnectLost();
  1034.                 return null;
  1035.             }
  1036.             catch (Exception ex)
  1037.             {
  1038.                 OnErrorOccurred(ex);
  1039.                 return null;
  1040.             }
  1041.         }
  1042.         /// <summary>
  1043.         /// 开始传输
  1044.         /// </summary>
  1045.         public override void Start()
  1046.         {
  1047.             base.Start();
  1048.             try
  1049.             {
  1050.                 BeginReceive();
  1051.                 _FileStream = new FileStream(FullFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
  1052.                 _TotalBlock = (int)(_FileStream.Length / (long)Consts.BlockSize) + 1;
  1053.                 _LastBlockSize = (int)(_FileStream.Length - ((long)_TotalBlock - 1) * (long)Consts.BlockSize);
  1054.             }
  1055.             catch (Exception ex)
  1056.             {
  1057.                 OnErrorOccurred(ex);
  1058.             }
  1059.         }
  1060.         /// <summary>
  1061.         /// 获取估计剩余时间
  1062.         /// </summary>
  1063.         public override TimeSpan TimeRemaining
  1064.         {
  1065.             get
  1066.             {
  1067.                 int BlockRemaining = _TotalBlock - _FinishedBlock.Count;
  1068.                 return TimeSpan.FromSeconds(BlockRemaining / BlockAverSpeed);
  1069.             }
  1070.         }
  1071.         /// <summary>
  1072.         /// 获取已完成的数据长度
  1073.         /// </summary>
  1074.         public override long FinishedSize
  1075.         {
  1076.             get
  1077.             {
  1078.                 return (long)_FinishedBlock.Count * (long)Consts.BlockSize;
  1079.             }
  1080.         }
  1081.         /// <summary>
  1082.         /// 同步发送区块
  1083.         /// </summary>
  1084.         /// <param name="BlockIndex">区块序号</param>
  1085.         /// <returns>发送的数据长度</returns>
  1086.         public int SendBlock(int BlockIndex)
  1087.         {
  1088.             try
  1089.             {
  1090.                 int ret = _Socket.EndSend(BeginSendBlock(BlockIndex, null, null));
  1091.                 OnBlockFinished(BlockIndex);
  1092.                 return ret;
  1093.             }
  1094.             catch (SocketException)
  1095.             {
  1096.                 OnConnectLost();
  1097.                 return 0;
  1098.             }
  1099.             catch (Exception ex)
  1100.             {
  1101.                 OnErrorOccurred(ex);
  1102.                 return 0;
  1103.             }
  1104.         }
  1105.         /// <summary>
  1106.         /// 异步发送区块并使用默认的回调方法
  1107.         /// </summary>
  1108.         /// <param name="BlockIndex">区块序号</param>
  1109.         public void SendBlockAsync(int BlockIndex)
  1110.         {
  1111.             BeginSendBlock(BlockIndex, SendCallback, BlockIndex);
  1112.         }
  1113.         /// <summary>
  1114.         /// 异步发送区块并使用指定的回调方法和参数
  1115.         /// </summary>
  1116.         /// <param name="BlockIndex">区块序号</param>
  1117.         public IAsyncResult BeginSendBlock(int BlockIndex, AsyncCallback callback, object state)
  1118.         {
  1119.             try
  1120.             {
  1121.                 if (!_IsAlive)
  1122.                     throw new InvalidOperationException("Is Not Alive");
  1123.                 if (BlockIndex >= _TotalBlock)
  1124.                     throw new ArgumentOutOfRangeException("BlockIndex");
  1125.                 byte[] ToSend = _Blocks[BlockIndex].GetBytes();
  1126.                 return _Socket.BeginSend(ToSend, 0, ToSend.Length, SocketFlags.None, callback, state);
  1127.             }
  1128.             catch (SocketException)
  1129.             {
  1130.                 OnConnectLost();
  1131.                 return null;
  1132.             }
  1133.             catch (Exception ex)
  1134.             {
  1135.                 OnErrorOccurred(ex);
  1136.                 return null;
  1137.             }
  1138.         }
  1139.         internal void ReceiveCallback(IAsyncResult ar)
  1140.         {
  1141.             bool ContinueReceive = true;
  1142.             int count = 0;
  1143.             try
  1144.             {
  1145.                 count = _Socket.EndReceive(ar);
  1146.             }
  1147.             catch (SocketException)
  1148.             {
  1149.                 OnConnectLost();
  1150.                 return;
  1151.             }
  1152.             catch (Exception ex)
  1153.             {
  1154.                 try
  1155.                 {
  1156.                     OnErrorOccurred(ex);
  1157.                 }
  1158.                 catch { return; }
  1159.             }
  1160.             try
  1161.             {
  1162.                 if (count == 0)
  1163.                     return;
  1164.                 switch (ReceiveBuf[0])
  1165.                 {
  1166.                     case Consts.StringHeader:
  1167.                         ContinueReceive = OnCommandReceived(ReceiveBuf.ToFTString());
  1168.                         break;
  1169.                     default:
  1170.                         throw new FormatException("Bad Header!");
  1171.                 }
  1172.             }
  1173.             catch (Exception ex)
  1174.             {
  1175.                 OnErrorOccurred(ex);
  1176.             }
  1177.             if (ContinueReceive)
  1178.             {
  1179.                 BeginReceive();
  1180.             }
  1181.         }
  1182.         /// <summary>
  1183.         /// 命令处理
  1184.         /// </summary>
  1185.         /// <param name="str">收到的命令</param>
  1186.         /// <returns>是否继续接收</returns>
  1187.         internal bool OnCommandReceived(string str)
  1188.         {
  1189.             if (CommandReceived != null)
  1190.                 CommandReceived(this, new CommandReceivedEventArgs(str));
  1191.             bool ContinueReceive = true;
  1192.             string[] Msg = str.Split(' ');
  1193.             if (Msg[0] == "Exit")
  1194.             {
  1195.                 OnAllFinished();
  1196.                 ContinueReceive = false;
  1197.                 Stop();
  1198.             }
  1199.             else if (Msg[0] == "GET")
  1200.             {
  1201.                 if (Msg[1] == "FileBlock")
  1202.                 {
  1203.                     int BlockIndex;
  1204.                     if (!int.TryParse(Msg[2], out BlockIndex))
  1205.                         throw new FormatException("Bad BlockIndex " + Msg[2]);
  1206.                     SendBlock(BlockIndex);
  1207.                 }
  1208.                 else if (Msg[1] == "BlockHash")
  1209.                 {
  1210.                     int BlockIndex;
  1211.                     if (!int.TryParse(Msg[2], out BlockIndex))
  1212.                         throw new FormatException("Bad BlockIndex " + Msg[2]);
  1213.                     byte[] hash = _Blocks[BlockIndex].DataHash;
  1214.                     SendStringAsync(string.Format("BlockHash {0} {1}", BlockIndex, BitConverter.ToInt32(hash, 0)));
  1215.                 }
  1216.                 else if (Msg[1] == "FileName")
  1217.                 {
  1218.                     SendStringAsync(string.Format("SET FileName {0}", FileName.DoReplace()));
  1219.                 }
  1220.                 else if (Msg[1] == "TotalBlock")
  1221.                 {
  1222.                     SendStringAsync(string.Format("SET TotalBlock {0}", _TotalBlock));
  1223.                 }
  1224.                 else if (Msg[1] == "LastBlockSize")
  1225.                 {
  1226.                     SendStringAsync(string.Format("SET LastBlockSize {0}", _LastBlockSize));
  1227.                 }
  1228.                 else
  1229.                     throw new FormatException("Bad Command " + Msg[1]);
  1230.             }
  1231.             else
  1232.                 throw new FormatException("Bad Command " + Msg[0]);
  1233.  
  1234.             return ContinueReceive;
  1235.         }
  1236.     }
  1237.     #endregion
  1238.  
  1239.     #region 接收端类
  1240.     /// <summary>
  1241.     /// 接收端
  1242.     /// 传输前接收端创建该类实例
  1243.     /// 设置必要属性后
  1244.     /// 调用Start()方法开始传输
  1245.     /// </summary>
  1246.     public class FileReceiver : FileTransmission
  1247.     {
  1248.         internal List<int> _ExistBlock;
  1249.         internal List<int> _CastBlock;
  1250.         /// <summary>
  1251.         /// 下载线程
  1252.         /// </summary>
  1253.         internal Thread _DownThread;
  1254.         public event BlockFinishedEventHandler BlockHashed;
  1255.         /// <summary>
  1256.         /// 开始异步接收
  1257.         /// </summary>
  1258.         internal override IAsyncResult BeginReceive()
  1259.         {
  1260.             InitializeReceiveBuf();
  1261.             try
  1262.             {
  1263.                 return _Socket.BeginReceive(ReceiveBuf, 0, ReceiveBuf.Length, SocketFlags.None, null, null);
  1264.             }
  1265.             catch (SocketException)
  1266.             {
  1267.                 OnConnectLost();
  1268.                 return null;
  1269.             }
  1270.             catch (Exception ex)
  1271.             {
  1272.                 OnErrorOccurred(ex);
  1273.                 return null;
  1274.             }
  1275.         }
  1276.         /// <summary>
  1277.         /// 获取估计剩余时间
  1278.         /// </summary>
  1279.         public override TimeSpan TimeRemaining
  1280.         {
  1281.             get
  1282.             {
  1283.                 int BlockRemaining = _TotalBlock - _FinishedBlock.Count - ((FileReceiver)this)._ExistBlock.Count;
  1284.                 return TimeSpan.FromSeconds(BlockRemaining / BlockAverSpeed);
  1285.             }
  1286.         }
  1287.         /// <summary>
  1288.         /// 获取已完成的数据长度
  1289.         /// </summary>
  1290.         public override long FinishedSize
  1291.         {
  1292.             get
  1293.             {
  1294.                 return ((long)_FinishedBlock.Count + (long)_ExistBlock.Count - 1) * (long)Consts.BlockSize + (long)_LastBlockSize;
  1295.             }
  1296.         }
  1297.         /// <summary>
  1298.         /// 开始传输
  1299.         /// </summary>
  1300.         public override void Start()
  1301.         {
  1302.             base.Start();
  1303.             try
  1304.             {
  1305.                 _CastBlock = new List<int>();
  1306.                 _ExistBlock = new List<int>();
  1307.                 _DownThread = new Thread(DownLoad);
  1308.                 _DownThread.IsBackground = true;
  1309.                 _DownThread.Name = "DownThread";
  1310.                 _DownThread.Start();
  1311.             }
  1312.             catch (Exception ex)
  1313.             {
  1314.                 OnErrorOccurred(ex);
  1315.             }
  1316.         }
  1317.         /// <summary>
  1318.         /// 中止传输
  1319.         /// </summary>
  1320.         /// <param name="ShutDownSocket">是否关闭Socket</param>
  1321.         public override void Stop(bool ShutDownSocket)
  1322.         {
  1323.             try
  1324.             {
  1325.                 if (_DownThread != null)
  1326.                 {
  1327.                     if ((_DownThread.ThreadState & ThreadState.Running) == ThreadState.Running)
  1328.                         _DownThread.Abort();
  1329.                 }
  1330.             }
  1331.             catch (Exception ex)
  1332.             {
  1333.                 OnErrorOccurred(ex);
  1334.             }
  1335.             base.Stop(ShutDownSocket);
  1336.         }
  1337.         internal string ReceiveString()
  1338.         {
  1339.             int count = 0;
  1340.             try
  1341.             {
  1342.                 count = _Socket.EndReceive(BeginReceive());
  1343.             }
  1344.             catch (Exception ex)
  1345.             {
  1346.                 OnConnectLost();
  1347.                 throw ex;
  1348.             }
  1349.             if (count == 0)
  1350.                 return null;
  1351.             else
  1352.                 return ReceiveBuf.ToFTString();
  1353.         }
  1354.         internal FileBlock ReceiveFileBlock()
  1355.         {
  1356.             MemoryStream mStream = new MemoryStream();
  1357.             while (true)
  1358.             {
  1359.                 int count = 0;
  1360.                 try
  1361.                 {
  1362.                     count = _Socket.EndReceive(BeginReceive());
  1363.                     if (count == 0) throw new Exception();
  1364.                 }
  1365.                 catch (Exception ex)
  1366.                 {
  1367.                     OnConnectLost();
  1368.                     throw ex;
  1369.                 }
  1370.                 mStream.Write(ReceiveBuf, 0, count);
  1371.                 try
  1372.                 {//接收到正确的区块则返回
  1373.                     return new FileBlock(this, mStream.ToArray());
  1374.                 }
  1375.                 catch (FileBlockException ex)
  1376.                 {//接收到不完整或错误的区块,若不完整则继续接收
  1377.                     if (mStream.Length >= Consts.NetBlockMaxSize)
  1378.                         throw ex;//区块已达到指定大小但仍然错误,则抛出错误
  1379.                 }
  1380.             }
  1381.         }
  1382.         /// <summary>
  1383.         /// 从发送端获取文件名
  1384.         /// </summary>
  1385.         public void GetFileName()
  1386.         {
  1387.             while (true)
  1388.             {
  1389.                 SendString("GET FileName");
  1390.                 string[] Msg = ReceiveString().Split(' ');
  1391.                 if (Msg[0] == "SET" && Msg[1] == "FileName")
  1392.                 {
  1393.                     FileName = Msg[2];
  1394.                     break;
  1395.                 }
  1396.             }
  1397.         }
  1398.         /// <summary>
  1399.         /// 从发送端获取区块总数
  1400.         /// </summary>
  1401.         public void GetTotalBlock()
  1402.         {
  1403.             while (true)
  1404.             {
  1405.                 SendString("GET TotalBlock");
  1406.                 string[] Msg = ReceiveString().Split(' ');
  1407.                 if (Msg[0] == "SET" && Msg[1] == "TotalBlock")
  1408.                 {
  1409.                     if (int.TryParse(Msg[2], out _TotalBlock))
  1410.                         break;
  1411.                 }
  1412.             }
  1413.         }
  1414.         /// <summary>
  1415.         /// 从发送端获取最后一个区块的大小
  1416.         /// </summary>
  1417.         public void GetLastBlockSize()
  1418.         {
  1419.             while (true)
  1420.             {
  1421.                 SendString("GET LastBlockSize");
  1422.                 string[] Msg = ReceiveString().Split(' ');
  1423.                 if (Msg[0] == "SET" && Msg[1] == "LastBlockSize")
  1424.                 {
  1425.                     if (int.TryParse(Msg[2], out _LastBlockSize))
  1426.                         break;
  1427.                 }
  1428.             }
  1429.         }
  1430.         /// <summary>
  1431.         /// 校验文件
  1432.         /// </summary>
  1433.         /// <returns>损坏或尚未下载的区块序号列表</returns>
  1434.         public List<int> HashFile()
  1435.         {
  1436.             _FileStream.Position = 0;
  1437.             _ExistBlock.Clear();
  1438.             for (int count = 0; _FileStream.Position < _FileStream.Length && count < _TotalBlock; count++)
  1439.             {//校验已存在的区块
  1440.                 FileBlock TestBlock = new FileBlock(this, count, true);
  1441.                 SendString(string.Format("GET BlockHash {0}", count));
  1442.                 string[] Msg = ReceiveString().Split(' ');
  1443.                 if (Msg[0] == "BlockHash")
  1444.                 {
  1445.                     if (Convert.ToInt32(Msg[1]) == count)
  1446.                     {
  1447.                         if (BitConverter.ToInt32(TestBlock.DataHash, 0) == Convert.ToInt32(Msg[2]))
  1448.                             _ExistBlock.Add(count);
  1449.                     }
  1450.                 }
  1451.                 if (BlockHashed != null)
  1452.                     BlockHashed(this, new BlockFinishedEventArgs(count));
  1453.             }
  1454.             int MaxExistBlockIndex;//已存在的区块最大序号
  1455.             try
  1456.             {
  1457.                 MaxExistBlockIndex = _ExistBlock.Max();
  1458.             }
  1459.             catch
  1460.             {
  1461.                 MaxExistBlockIndex = 0;
  1462.             }
  1463.             List<int> BlockRemaining = new List<int>();
  1464.             for (int index = 0; index < _TotalBlock; )
  1465.             {//计算仍需传输的区块
  1466.                 if (index <= MaxExistBlockIndex)
  1467.                 {
  1468.                     if (_ExistBlock.Exists(=> a == index))
  1469.                     {
  1470.                         index++;
  1471.                         continue;
  1472.                     }
  1473.                 }
  1474.                 BlockRemaining.Add(index++);
  1475.             }
  1476.             return BlockRemaining;
  1477.         }
  1478.         /// <summary>
  1479.         /// 接收整个文件
  1480.         /// </summary>
  1481.         internal void DownLoad()
  1482.         {
  1483.             try
  1484.             {
  1485.                 if (string.IsNullOrEmpty(FilePath))//未指定路径时默认为接收程序所在路径
  1486.                     FilePath = Environment.CurrentDirectory;
  1487.                 if (string.IsNullOrEmpty(FileName))//未指定文件名时从发送端获取
  1488.                 {
  1489.                     GetFileName();
  1490.                 }
  1491.                 _FileStream = new FileStream(FullFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);//temp
  1492.                 GetTotalBlock();
  1493.                 GetLastBlockSize();
  1494.                 List<int> BlockRemaining = HashFile();
  1495.                 if (_FileStream.Length > TotalSize)//如果已存在的文件比目标文件长则截断它
  1496.                     _FileStream.SetLength(TotalSize);
  1497.                 _StartTime = DateTime.Now;
  1498.                 foreach (int index in BlockRemaining)
  1499.                 {
  1500.                     FileBlock Block;
  1501.                     while (true)
  1502.                     {
  1503.                         SendString(string.Format("GET FileBlock {0}", index));
  1504.                         try
  1505.                         {
  1506.                             Block = ReceiveFileBlock();
  1507.                             break;
  1508.                         }
  1509.                         catch (FileBlockException)
  1510.                         {//接收到错误的区块,抛弃该数据并重新请求
  1511.                             _CastBlock.Add(index);
  1512.                         }
  1513.                         catch (Exception ex)
  1514.                         {
  1515.                             OnErrorOccurred(ex);
  1516.                         }
  1517.                     }
  1518.                     while (true)
  1519.                     {
  1520.                         try
  1521.                         {
  1522.                             _Blocks[index] = Block;//写入区块
  1523.                             OnBlockFinished(index);
  1524.                             break;
  1525.                         }
  1526.                         catch (IOException ex)
  1527.                         {//磁盘写入错误时
  1528.                             try
  1529.                             {
  1530.                                 OnErrorOccurred(ex);
  1531.                                 //重试
  1532.                             }
  1533.                             catch
  1534.                             {//退出
  1535.                                 Stop();
  1536.                                 return;
  1537.                             }
  1538.                         }
  1539.                         catch (Exception ex)
  1540.                         {
  1541.                             OnErrorOccurred(ex);
  1542.                         }
  1543.                     }
  1544.                 }
  1545.                 SendStringAsync("Exit");
  1546.                 _Blocks.WriteAllBlock();
  1547.                 OnAllFinished();
  1548.                 Stop();
  1549.             }
  1550.             catch (SocketException) { }
  1551.             catch (Exception ex)
  1552.             {
  1553.                 OnErrorOccurred(ex);
  1554.             }
  1555.         }
  1556.     }
  1557.     #endregion
  1558. }

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

 
 
 
标签: C#网络

一个C#文件传输模块,支持断点续传的更多相关文章

  1. 在ASP.NET中支持断点续传下载大文件(ZT)

    IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag         客户端每次提交 ...

  2. 打印 上一主题 下一主题 利用cURL实现单个文件分多段同时下载,支持断点续传(修订版)

      利用cURL实现单个文件分多段同时下载,支持断点续传(修订版) [复制链接] 摘自 http://bbs.chinaunix.net/thread-917952-1-1.html 在ubuntu下 ...

  3. FTP文件上传 支持断点续传 并 打印下载进度(二) —— 单线程实现

    这个就看代码,哈哈哈哈哈  需要用到的jar包是: <dependency> <groupId>commons-net</groupId> <artifact ...

  4. ASP.NET文件下载各种方式比较:对性能的影响、对大文件的支持、对断点续传和多线程下载的支持

    asp.net里提供了多种方式,从服务器端向客户端写文件流,实现客户端下载文件.这种技术在做防下载系统时比较有用处.主些技术主要有:WriteFile.TransmitFile和BinaryWrite ...

  5. 【FTP】FTP文件上传下载-支持断点续传

    Jar包:apache的commons-net包: 支持断点续传 支持进度监控(有时出不来,搞不清原因) 相关知识点 编码格式: UTF-8等; 文件类型: 包括[BINARY_FILE_TYPE(常 ...

  6. edtftpj让Java上传FTP文件支持断点续传

    在用Java实现FTP上传文件功能时,特别是上传大文件的时候,可以需要这样的功能:程序在上传的过程中意外终止了,文件传了一大半,想从断掉了地方继续传:或者想做类似迅雷下载类似的功能,文件太大,今天传一 ...

  7. 高性能TcpServer(C#) - 4.文件通道(处理:文件分包,支持断点续传)

    高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...

  8. 【SFTP】使用Jsch实现Sftp文件下载-支持断点续传和进程监控

    参考上篇文章: <[SFTP]使用Jsch实现Sftp文件下载-支持断点续传和进程监控>:http://www.cnblogs.com/ssslinppp/p/6248763.html  ...

  9. ASIHTTPRequest下载示例(支持断点续传)

    一.创建网络请求队列 首先,创建网络请求队列,如下: ASINetworkQueue   *que = [[ASINetworkQueue alloc] init]; self.netWorkQueu ...

随机推荐

  1. Java8 时区DateTime API

    原文:http://www.yiibai.com/java8/java8_zoneddateapi.html 时区日期时间的API正在使用当时区要被考虑时. 让我们来看看他们的操作. 选择使用任何编辑 ...

  2. 【js html】对于<img>图片的引用填充,src可以给什么值?

    平时多见的<img>的使用,常见于如下: <img class="img-responsive img-rounded" src="static/img ...

  3. centos安装配置nginx,ssl生产和配置教程

    [一]nginx安装nginx安装带ssl扩展: cd /usr/local/src #进入用户目录wget http://nginx.org/download/nginx-1.15.0.tar.gz ...

  4. BUPT 2012复试机考 4T

    题目描述 我们都学习过计算机网络,知道网络层IP协议数据包的头部格式如下: 其中IHL表示IP头的长度,单位是4字节:总长表示整个数据包的长度,单位是1字节.传输层的TCP协议数据段的头部格式如下:  ...

  5. Error: cannot call methods on draggable prior to initialization; attempted to call

    cannot call methods on draggable prior to initialization; attempted to call  报这个问题的根本原因是由于你的引用文件有问题 ...

  6. react jsx 数组变量的写法

    1.通过 map 方法 var students = ["张三然","李慧思","赵思然","孙力气","王萌 ...

  7. 不能选择sublime作为默认打开方式的解决办法

    Sublime Text 绿色版删除后无法设置为默认打开方式…而且网上也没有给出明确的解决办法 注册表的解决办法: 删除 HKEY_CURRENT_USER\Software\Classes\Appl ...

  8. 项目Beta冲刺(团队5/7)

    项目Beta冲刺(团队5/7) 团队名称: 云打印 作业要求: 项目Beta冲刺(团队) 作业目标: 完成项目Beta版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 陈宇 ...

  9. WPF数据验证(5)―― 错误模板

    <Style TargetType="{x:Type TextBox}">            <Setter Property="Validatio ...

  10. Kubernetes实战阅读笔记--1、介绍

    1.业界根据云计算提供服务资源的类型将其划分为三大类: 基础设施即服务(Infrastructure-as-a-Service,IaaS).平台即服务(Platform-as-a-Service,Pa ...