最近做一个程序需要传送文件,在网上找了好久也没找到好用的方案,于是自己写了一个,与大家分享,希望大家帮忙改进,拍砖欢迎~
文件采取分块发送,每块单独校验,能够保证文件的完整性.同时还提供磁盘缓存功能.
经过实际测试,通过局域网(有线和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
    #region CRC32算法
    /// <summary>
    /// CRC32快速检测算法
    /// 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ZZJ_4Ever/archive/2009/03/31/4038551.aspx
    /// 有稍作修改
    /// </summary>
    public static class CRC32
    {
        static UInt32[] crcTable = {   
         0x0, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,   
         0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,   
         0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,   
         0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,   
         0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,   
         0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,   
         0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,   
         0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,   
         0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x6b6b51f, 0x9fbfe4a5, 0xe8b8d433,   
         0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x86d3d2d, 0x91646c97, 0xe6635c01,   
         0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,   
         0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,   
         0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,   
         0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,   
         0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,   
         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,   
         0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x4db2615, 0x73dc1683,   
         0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0xa00ae27, 0x7d079eb1,   
         0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,   
         0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,   
         0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,   
         0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,   
         0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,   
         0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,   
         0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713,   
         0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21,   
         0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,   
         0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,   
         0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,   
         0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,   
         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,   
         0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,                          
                                   };
        public static int GetCRC32(byte[] bytes)
        {
            int iCount = bytes.Length;
            UInt32 crc = 0xFFFFFFFF;
            for (int i = 0; i < iCount; i++)
            {
                crc = ((crc >> 8) & 0x00FFFFFF) ^ crcTable[(crc ^ bytes[i]) & 0xFF];
            }
            UInt32 temp = crc ^ 0xFFFFFFFF;
            int t = (int)temp;
            return (t);
        }
    }
    #endregion     #region 一些常量和扩展方法
    /// <summary>
    /// 一些常量和扩展方法
    /// </summary>
    public static class Consts
    {
        /// <summary>
        /// 文件区块数据标头
        /// </summary>
        public const byte FileBlockHeader = 0;
        /// <summary>
        /// 字符串信息标头
        /// </summary>
        public const byte StringHeader = 1;
        /// <summary>
        /// 分块大小1MB
        /// </summary>
        public const int BlockSize = 1048576;
        /// <summary>
        /// 网络上传送的数据包最大大小
        /// </summary>
        public const int NetBlockMaxSize = BlockSize + 9;
        /// <summary>
        /// 默认磁盘缓存大小(单位:区块数)
        /// </summary>
        public const int DefaultIOBufferSize = 8;
        /// <summary>
        /// 空格
        /// </summary>
        public const string Space = " ";
        /// <summary>
        /// 空格替代符
        /// </summary>
        public const string SpaceReplacement = @"<SPACE>";
        /// <summary>
        /// 获取校验值
        /// </summary>
        /// <param name="bytes">输入数据</param>
        /// <returns>输出的校验值</returns>
        public static byte[] GetHash(this byte[] bytes)
        {
            return BitConverter.GetBytes(CRC32.GetCRC32(bytes));
        }
        /// <summary>
        /// 比较两二进制数据内容是否完全相同(用于校验值的比较)
        /// </summary>
        /// <param name="THIS">数据一</param>
        /// <param name="obj">数据二</param>
        public static bool BytesEqual(this byte[] THIS, byte[] obj)
        {
            if (THIS.Length != obj.Length)
                return false;
            for (int index = 0; index < obj.Length; index++)
            {
                if (THIS[index] != obj[index])
                    return false;
            }
            return true;
        }
        /// <summary>
        /// 将指令字符串转化为二进制数据并添加标头
        /// </summary>
        public static byte[] ToBytes(this string str_input)
        {
            byte[] strdata = Encoding.UTF8.GetBytes(str_input);
            byte[] output = new byte[1 + strdata.Length];
            output[0] = StringHeader;
            System.Array.Copy(strdata, 0, output, 1, strdata.Length);
            return output;
        }
        /// <summary>
        /// 将二进制数据转化为指令字符串
        /// </summary>
        public static string ToFTString(this byte[] bytes_input)
        {
            if (bytes_input[0] != StringHeader)
                throw new FormatException("Bad Header!");
            return Encoding.UTF8.GetString(bytes_input, 1, bytes_input.Length - 1).TrimEnd('\0');
        }
        /// <summary>
        /// 替换可能会对命令解析造成干扰的字符
        /// </summary>
        public static string DoReplace(this string str_input)
        {
            return str_input.Replace(Space, SpaceReplacement);
        }
        /// <summary>
        /// 还原被替换的字符
        /// </summary>
        public static string DeReplace(this string str_input)
        {
            return str_input.Replace(SpaceReplacement, Space);
        }
    }
    #endregion     #region 一些委托
    public delegate void BlockFinishedEventHandler(object sender, BlockFinishedEventArgs e);
    public delegate void CommandReceivedEventHandler(object sender, CommandReceivedEventArgs e);
    public delegate void FileTransmissionErrorOccurEventHandler(object sender,FileTransmissionErrorOccurEventArgs e);
    public delegate void Delegate_SendBlocks(int Start, int End);
    public delegate void Delegate_Void_Bool(bool logic);
    public delegate int Delegate_Int_Int(int value);
    #endregion     #region 文件区块类
    public class FileBlockException : Exception
    {
        public enum ErrorCode
        {
            BadHeader,
            BadIndex,
            IllegalFileBlockSize,
            ChecksumError,
        }
        public ErrorCode Code { get; set; }
        public FileBlockException(string message, ErrorCode ErrorCode)
            : base(message)
        {
            Code = ErrorCode;
        }
    }
    /// <summary>
    /// 文件区块类
    /// </summary>
    public class FileBlock : IComparable<FileBlock>
    {
        /// <summary>
        /// 与该区块关联的传输对象
        /// </summary>
        internal FileTransmission _Task;
        /// <summary>
        /// 与该区块关联的FileStream
        /// </summary>
        internal FileStream _FileStream;
        /// <summary>
        /// 文件数据
        /// </summary>
        internal byte[] _Data;
        /// <summary>
        /// 数据长度
        /// </summary>
        internal int _DataLength;
        /// <summary>
        /// 数据的Hash值
        /// </summary>
        internal byte[] _DataHash;
        /// <summary>
        /// 获取或设置该区块的序号(该区块在文件中的位置)
        /// </summary>
        public int Index { get; set; }
        /// <summary>
        /// 获取该区块的数据长度
        /// </summary>
        public int DataLength { get { return _DataLength; } }
        /// <summary>
        /// 获取该数据块的校验值
        /// </summary>
        public byte[] DataHash { get { return _DataHash; } }
        /// <summary>
        /// 构造函数
        /// 用于从文件读入区块
        /// </summary>
        /// <param name="fStream">输入的文件流</param>
        /// <param name="BlockIndex">分块位置</param>
        /// <param name="ReadOnCreated">是否立即从文件读取数据</param>
        public FileBlock(FileTransmission TransmissionTask, int BlockIndex, bool ReadOnCreated)
        {
            _Task = TransmissionTask;
            _FileStream = _Task.FileStream;
            Index = BlockIndex;
            if (ReadOnCreated)
                this.Read(true);
        }
        /// <summary>
        /// 构造函数
        /// 用于从二进制数据读入区块
        /// </summary>
        /// <param name="fStream">要保存的文件流</param>
        /// <param name="ReceivedData">输入的二进制数据</param>
        public FileBlock(FileTransmission TransmissionTask, byte[] ReceivedData)
        {
            _Task = TransmissionTask;
            _FileStream = _Task.FileStream;
            if (ReceivedData[0] != Consts.FileBlockHeader)
                throw new FileBlockException("Bad Header!", FileBlockException.ErrorCode.BadHeader);
            Index = BitConverter.ToInt32(ReceivedData, 1);
            _DataLength = ReceivedData.Length - 9;
            if (_DataLength > Consts.BlockSize)
                throw new FileBlockException("Illegal FileBlock Size!", FileBlockException.ErrorCode.IllegalFileBlockSize);
            _Data = new byte[_DataLength];
            _DataHash = new byte[4];
            System.Array.Copy(ReceivedData, 5, _DataHash, 0, 4);
            System.Array.Copy(ReceivedData, 9, _Data, 0, _DataLength);
            if (!_DataHash.BytesEqual(_Data.GetHash()))
                throw new FileBlockException("Error Hash!", FileBlockException.ErrorCode.ChecksumError);
        }
        /// <summary>
        /// 从文件读入
        /// </summary>
        /// <param name="CalcHashAfterRead">是否在读取后立即计算校验值</param>
        /// <returns>读取块的大小</returns>
        public int Read(bool CalcHashAfterRead)
        {
            _Data = new byte[Consts.BlockSize];
            lock (_FileStream)
            {
                _FileStream.Position = (long)Index * (long)Consts.BlockSize;
                _DataLength = _FileStream.Read(_Data, 0, Consts.BlockSize);
            }
            if (_Data.Length != _DataLength)
            {
                byte[] old = _Data;
                _Data = new byte[_DataLength];
                System.Array.Copy(old, _Data, _DataLength);
            }
            if (CalcHashAfterRead)
                CalcHash();
            return _DataLength;
        }
        /// <summary>
        /// 计算校验值
        /// </summary>
        /// <returns>校验值</returns>
        public byte[] CalcHash()
        {
            return _DataHash = _Data.GetHash();
        }
        /// <summary>
        /// 将该区块写入文件
        /// </summary>
        public void Write()
        {
            lock (_FileStream)
            {
                _FileStream.Position = (long)Index * (long)Consts.BlockSize;
                _FileStream.Write(_Data, 0, _DataLength);
            }
        }
        /// <summary>
        /// 转化为二进制数据以传输
        /// </summary>
        /// <returns></returns>
        public byte[] GetBytes()
        {
            MemoryStream mStream = new MemoryStream(1 + 4 + 4 + _DataLength);
            byte[] Header = new byte[1] { Consts.FileBlockHeader };
            mStream.Write(Header, 0, 1);
            mStream.Write(BitConverter.GetBytes(Index), 0, 4);
            mStream.Write(_DataHash, 0, 4);
            mStream.Write(_Data, 0, _DataLength);
            return mStream.ToArray();
        }
        int System.IComparable<FileBlock>.CompareTo(FileBlock obj)
        {
            return (Index as IComparable<int>).CompareTo(obj.Index);
        }
    }
    #endregion     #region 事件参数类
    public class BlockFinishedEventArgs : EventArgs
    {
        public int BlockIndex { get; set; }
        public BlockFinishedEventArgs(int BlockIndex) { this.BlockIndex = BlockIndex; }
    }
    public class CommandReceivedEventArgs : EventArgs
    {
        public string CommandLine { get; set; }
        public CommandReceivedEventArgs(string CommandLine) { this.CommandLine = CommandLine; }
    }
    public class FileTransmissionErrorOccurEventArgs : EventArgs
    {
        public Exception InnerException { get; set; }
        /// <summary>
        /// 指示是否继续运行
        /// </summary>
        public bool Continue { get; set; }
        public FileTransmissionErrorOccurEventArgs(Exception innerException)
        {
            InnerException = innerException;
            Continue = false;
        }
    }
    #endregion     #region 文件区块抽象集合类
    /// <summary>
    /// 文件区块的抽象集合
    /// 之所以说抽象是因为该集合并不存储实际的区块(缓存区除外)
    /// 而是通过一个索引器来读写文件
    /// 并提供磁盘缓存
    /// </summary>
    public class FileBlockCollection
    {
        /// <summary>
        /// 与该区块关联的传输对象
        /// </summary>
        internal FileTransmission _Task;
        /// <summary>
        /// 与该区块关联的FileStream
        /// </summary>
        internal FileStream _FileStream;
        internal bool _EnabledIOBuffer;
        /// <summary>
        /// 磁盘缓存区
        /// </summary>
        internal Dictionary<int, FileBlock> _IOBuffer;         public FileBlockCollection(FileTransmission TransmissionTask)
        {
            _Task = TransmissionTask;
            _FileStream = _Task.FileStream;
            _IOBufferSize = Consts.DefaultIOBufferSize;
        }
        /// <summary>
        /// 获取或设置一个值,该值指示是否启用磁盘缓存
        /// </summary>
        internal bool EnabledIOBuffer
        {
            get { return _EnabledIOBuffer; }
            set
            {
                _EnabledIOBuffer = value;
                if (value)
                    _IOBuffer = new Dictionary<int, FileBlock>();
                else
                {
                    if (_Task is FileReceiver)
                        WriteAllBlock();
                    _IOBuffer = null;
                }
            }
        }
        internal int _IOBufferSize;
        /// <summary>
        /// 获取已接收或已发送的区块序号列表
        /// </summary>
        public List<int> Finished { get { return _Task._FinishedBlock; } }
        /// <summary>
        /// 获取已存在(Hash成功)的区块序号列表
        /// </summary>
        public List<int> Exist
        {
            get
            {
                if (_Task is FileReceiver)
                    return ((FileReceiver)_Task)._ExistBlock;
                else
                    return null;
            }
        }
        /// <summary>
        /// 获取被丢弃的区块序号列表
        /// </summary>
        public List<int> Cast
        {
            get
            {
                if (_Task is FileReceiver)
                    return ((FileReceiver)_Task)._CastBlock;
                else
                    return null;
            }
        }
        /// <summary>
        /// 获取总区块数
        /// </summary>
        public int Count { get { return _Task._TotalBlock; } }
        /// <summary>
        /// 获取有效区块数(已存在+已接收)
        /// </summary>
        public int CountValid
        {
            get
            {
                if (_Task is FileReceiver)
                    return _Task._FinishedBlock.Count + ((FileReceiver)_Task)._ExistBlock.Count;
                else
                    return _Task._FinishedBlock.Count;             }
        }
        /// <summary>
        /// 将缓存中的区块全部写入磁盘
        /// </summary>
        /// <returns>写入的区块数量</returns>
        public int WriteAllBlock()
        {
            if (!_EnabledIOBuffer)
                return -1;
            int count = 0;
            lock (_IOBuffer)
            {
                foreach (var b in _IOBuffer)
                {
                    b.Value.Write();
                    count++;
                }
                if (count != _IOBuffer.Count)
                    throw new IOException("Can not Write All FileBlocks!");
                _IOBuffer.Clear();
            }
            return count;
        }
        /// <summary>
        /// 读取数据以填充缓存
        /// </summary>
        /// <param name="StartIndex">起始区块</param>
        /// <returns>读取的区块数量</returns>
        public int FillIOBuffer(int StartIndex)
        {
            int Index;
            lock (_IOBuffer)
            {
                _IOBuffer.Clear();
                for (Index = StartIndex; _IOBuffer.Count < _IOBufferSize && Index < _Task.Blocks.Count; Index++)
                {
                    _IOBuffer.Add(Index, new FileBlock(_Task, Index, true));
                }
            }
            return Index - StartIndex;
        }
        /// <summary>
        /// 异步填充缓存
        /// </summary>
        /// <param name="StartIndex">起始区块</param>
        public IAsyncResult BeginFillIOBuffer(int StartIndex,AsyncCallback callback,object state)
        {
            return new Delegate_Int_Int(FillIOBuffer).BeginInvoke(StartIndex, callback, state);
        }
        /// <summary>
        /// 写入区块
        /// </summary>
        /// <param name="value">区块对象</param>
        public void Write(FileBlock value)
        {
            if (_EnabledIOBuffer)
            {
                if (_IOBuffer.Count >= _IOBufferSize)
                    WriteAllBlock();
                lock (_IOBuffer)
                    _IOBuffer.Add(value.Index, value);
            }
            else
                value.Write();
        }
        /// <summary>
        /// 读取或写入区块
        /// </summary>
        /// <param name="BlockIndex">区块序号</param>
        public FileBlock this[int BlockIndex]
        {
            get
            {
                FileBlock output;
                if (_EnabledIOBuffer)
                {
                    
                    bool IsInBuf;
                    lock (_IOBuffer)
                        IsInBuf = _IOBuffer.TryGetValue(BlockIndex, out output);
                    if (IsInBuf)
                        return output;
                    else
                    {
                        output = new FileBlock(_Task, BlockIndex, true);
                        BeginFillIOBuffer(BlockIndex + 1, null, null);
                    }
                }
                else
                    output = new FileBlock(_Task, BlockIndex, true);
                return output;
            }
            set
            {
                if (BlockIndex != value.Index)
                    throw new FileBlockException("Bad Index!", FileBlockException.ErrorCode.BadIndex);
                Write(value);
            }
        }
    }
    #endregion     #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     #region 发送端类
    /// <summary>
    /// 发送端
    /// 传输前发送端创建该类实例
    /// 设置必要属性后
    /// 调用Start()方法开始传输
    /// </summary>
    public class FileSender : FileTransmission
    {
        /// <summary>
        /// 接收到命令时发生
        /// </summary>
        public event CommandReceivedEventHandler CommandReceived;
        /// <summary>
        /// 开始异步接收
        /// </summary>
        internal override IAsyncResult BeginReceive()
        {
            InitializeReceiveBuf();
            try
            {
                return _Socket.BeginReceive(ReceiveBuf, 0, ReceiveBuf.Length, SocketFlags.None, ReceiveCallback, null);
            }
            catch (SocketException)
            {
                OnConnectLost();
                return null;
            }
            catch (Exception ex)
            {
                OnErrorOccurred(ex);
                return null;
            }
        }
        /// <summary>
        /// 开始传输
        /// </summary>
        public override void Start()
        {
            base.Start();
            try
            {
                BeginReceive();
                _FileStream = new FileStream(FullFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
                _TotalBlock = (int)(_FileStream.Length / (long)Consts.BlockSize) + 1;
                _LastBlockSize = (int)(_FileStream.Length - ((long)_TotalBlock - 1) * (long)Consts.BlockSize);
            }
            catch (Exception ex)
            {
                OnErrorOccurred(ex);
            }
        }
        /// <summary>
        /// 获取估计剩余时间
        /// </summary>
        public override TimeSpan TimeRemaining
        {
            get
            {
                int BlockRemaining = _TotalBlock - _FinishedBlock.Count;
                return TimeSpan.FromSeconds(BlockRemaining / BlockAverSpeed);
            }
        }
        /// <summary>
        /// 获取已完成的数据长度
        /// </summary>
        public override long FinishedSize
        {
            get
            {
                return (long)_FinishedBlock.Count * (long)Consts.BlockSize;
            }
        }
        /// <summary>
        /// 同步发送区块
        /// </summary>
        /// <param name="BlockIndex">区块序号</param>
        /// <returns>发送的数据长度</returns>
        public int SendBlock(int BlockIndex)
        {
            try
            {
                int ret = _Socket.EndSend(BeginSendBlock(BlockIndex, null, null));
                OnBlockFinished(BlockIndex);
                return ret;
            }
            catch (SocketException)
            {
                OnConnectLost();
                return 0;
            }
            catch (Exception ex)
            {
                OnErrorOccurred(ex);
                return 0;
            }
        }
        /// <summary>
        /// 异步发送区块并使用默认的回调方法
        /// </summary>
        /// <param name="BlockIndex">区块序号</param>
        public void SendBlockAsync(int BlockIndex)
        {
            BeginSendBlock(BlockIndex, SendCallback, BlockIndex);
        }
        /// <summary>
        /// 异步发送区块并使用指定的回调方法和参数
        /// </summary>
        /// <param name="BlockIndex">区块序号</param>
        public IAsyncResult BeginSendBlock(int BlockIndex, AsyncCallback callback, object state)
        {
            try
            {
                if (!_IsAlive)
                    throw new InvalidOperationException("Is Not Alive");
                if (BlockIndex >= _TotalBlock)
                    throw new ArgumentOutOfRangeException("BlockIndex");
                byte[] ToSend = _Blocks[BlockIndex].GetBytes();
                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 ReceiveCallback(IAsyncResult ar)
        {
            bool ContinueReceive = true;
            int count = 0;
            try
            {
                count = _Socket.EndReceive(ar);
            }
            catch (SocketException)
            {
                OnConnectLost();
                return;
            }
            catch (Exception ex)
            {
                try
                {
                    OnErrorOccurred(ex);
                }
                catch { return; }
            }
            try
            {
                if (count == 0)
                    return;
                switch (ReceiveBuf[0])
                {
                    case Consts.StringHeader:
                        ContinueReceive = OnCommandReceived(ReceiveBuf.ToFTString());
                        break;
                    default:
                        throw new FormatException("Bad Header!");
                }
            }
            catch (Exception ex)
            {
                OnErrorOccurred(ex);
            }
            if (ContinueReceive)
            {
                BeginReceive();
            }
        }
        /// <summary>
        /// 命令处理
        /// </summary>
        /// <param name="str">收到的命令</param>
        /// <returns>是否继续接收</returns>
        internal bool OnCommandReceived(string str)
        {
            if (CommandReceived != null)
                CommandReceived(this, new CommandReceivedEventArgs(str));
            bool ContinueReceive = true;
            string[] Msg = str.Split(' ');
            if (Msg[0] == "Exit")
            {
                OnAllFinished();
                ContinueReceive = false;
                Stop();
            }
            else if (Msg[0] == "GET")
            {
                if (Msg[1] == "FileBlock")
                {
                    int BlockIndex;
                    if (!int.TryParse(Msg[2], out BlockIndex))
                        throw new FormatException("Bad BlockIndex " + Msg[2]);
                    SendBlock(BlockIndex);
                }
                else if (Msg[1] == "BlockHash")
                {
                    int BlockIndex;
                    if (!int.TryParse(Msg[2], out BlockIndex))
                        throw new FormatException("Bad BlockIndex " + Msg[2]);
                    byte[] hash = _Blocks[BlockIndex].DataHash;
                    SendStringAsync(string.Format("BlockHash {0} {1}", BlockIndex, BitConverter.ToInt32(hash, 0)));
                }
                else if (Msg[1] == "FileName")
                {
                    SendStringAsync(string.Format("SET FileName {0}", FileName.DoReplace()));
                }
                else if (Msg[1] == "TotalBlock")
                {
                    SendStringAsync(string.Format("SET TotalBlock {0}", _TotalBlock));
                }
                else if (Msg[1] == "LastBlockSize")
                {
                    SendStringAsync(string.Format("SET LastBlockSize {0}", _LastBlockSize));
                }
                else
                    throw new FormatException("Bad Command " + Msg[1]);
            }
            else
                throw new FormatException("Bad Command " + Msg[0]);             return ContinueReceive;
        }
    }
    #endregion     #region 接收端类
    /// <summary>
    /// 接收端
    /// 传输前接收端创建该类实例
    /// 设置必要属性后
    /// 调用Start()方法开始传输
    /// </summary>
    public class FileReceiver : FileTransmission
    {
        internal List<int> _ExistBlock;
        internal List<int> _CastBlock;
        /// <summary>
        /// 下载线程
        /// </summary>
        internal Thread _DownThread;
        public event BlockFinishedEventHandler BlockHashed;
        /// <summary>
        /// 开始异步接收
        /// </summary>
        internal override IAsyncResult BeginReceive()
        {
            InitializeReceiveBuf();
            try
            {
                return _Socket.BeginReceive(ReceiveBuf, 0, ReceiveBuf.Length, SocketFlags.None, null, null);
            }
            catch (SocketException)
            {
                OnConnectLost();
                return null;
            }
            catch (Exception ex)
            {
                OnErrorOccurred(ex);
                return null;
            }
        }
        /// <summary>
        /// 获取估计剩余时间
        /// </summary>
        public override TimeSpan TimeRemaining
        {
            get
            {
                int BlockRemaining = _TotalBlock - _FinishedBlock.Count - ((FileReceiver)this)._ExistBlock.Count;
                return TimeSpan.FromSeconds(BlockRemaining / BlockAverSpeed);
            }
        }
        /// <summary>
        /// 获取已完成的数据长度
        /// </summary>
        public override long FinishedSize
        {
            get
            {
                return ((long)_FinishedBlock.Count + (long)_ExistBlock.Count - 1) * (long)Consts.BlockSize + (long)_LastBlockSize;
            }
        }
        /// <summary>
        /// 开始传输
        /// </summary>
        public override void Start()
        {
            base.Start();
            try
            {
                _CastBlock = new List<int>();
                _ExistBlock = new List<int>();
                _DownThread = new Thread(DownLoad);
                _DownThread.IsBackground = true;
                _DownThread.Name = "DownThread";
                _DownThread.Start();
            }
            catch (Exception ex)
            {
                OnErrorOccurred(ex);
            }
        }
        /// <summary>
        /// 中止传输
        /// </summary>
        /// <param name="ShutDownSocket">是否关闭Socket</param>
        public override void Stop(bool ShutDownSocket)
        {
            try
            {
                if (_DownThread != null)
                {
                    if ((_DownThread.ThreadState & ThreadState.Running) == ThreadState.Running)
                        _DownThread.Abort();
                }
            }
            catch (Exception ex)
            {
                OnErrorOccurred(ex);
            }
            base.Stop(ShutDownSocket);
        }
        internal string ReceiveString()
        {
            int count = 0;
            try
            {
                count = _Socket.EndReceive(BeginReceive());
            }
            catch (Exception ex)
            {
                OnConnectLost();
                throw ex;
            }
            if (count == 0)
                return null;
            else
                return ReceiveBuf.ToFTString();
        }
        internal FileBlock ReceiveFileBlock()
        {
            MemoryStream mStream = new MemoryStream();
            while (true)
            {
                int count = 0;
                try
                {
                    count = _Socket.EndReceive(BeginReceive());
                    if (count == 0) throw new Exception();
                }
                catch (Exception ex)
                {
                    OnConnectLost();
                    throw ex;
                }
                mStream.Write(ReceiveBuf, 0, count);
                try
                {//接收到正确的区块则返回
                    return new FileBlock(this, mStream.ToArray());
                }
                catch (FileBlockException ex)
                {//接收到不完整或错误的区块,若不完整则继续接收
                    if (mStream.Length >= Consts.NetBlockMaxSize)
                        throw ex;//区块已达到指定大小但仍然错误,则抛出错误
                }
            }
        }
        /// <summary>
        /// 从发送端获取文件名
        /// </summary>
        public void GetFileName()
        {
            while (true)
            {
                SendString("GET FileName");
                string[] Msg = ReceiveString().Split(' ');
                if (Msg[0] == "SET" && Msg[1] == "FileName")
                {
                    FileName = Msg[2];
                    break;
                }
            }
        }
        /// <summary>
        /// 从发送端获取区块总数
        /// </summary>
        public void GetTotalBlock()
        {
            while (true)
            {
                SendString("GET TotalBlock");
                string[] Msg = ReceiveString().Split(' ');
                if (Msg[0] == "SET" && Msg[1] == "TotalBlock")
                {
                    if (int.TryParse(Msg[2], out _TotalBlock))
                        break;
                }
            }
        }
        /// <summary>
        /// 从发送端获取最后一个区块的大小
        /// </summary>
        public void GetLastBlockSize()
        {
            while (true)
            {
                SendString("GET LastBlockSize");
                string[] Msg = ReceiveString().Split(' ');
                if (Msg[0] == "SET" && Msg[1] == "LastBlockSize")
                {
                    if (int.TryParse(Msg[2], out _LastBlockSize))
                        break;
                }
            }
        }
        /// <summary>
        /// 校验文件
        /// </summary>
        /// <returns>损坏或尚未下载的区块序号列表</returns>
        public List<int> HashFile()
        {
            _FileStream.Position = 0;
            _ExistBlock.Clear();
            for (int count = 0; _FileStream.Position < _FileStream.Length && count < _TotalBlock; count++)
            {//校验已存在的区块
                FileBlock TestBlock = new FileBlock(this, count, true);
                SendString(string.Format("GET BlockHash {0}", count));
                string[] Msg = ReceiveString().Split(' ');
                if (Msg[0] == "BlockHash")
                {
                    if (Convert.ToInt32(Msg[1]) == count)
                    {
                        if (BitConverter.ToInt32(TestBlock.DataHash, 0) == Convert.ToInt32(Msg[2]))
                            _ExistBlock.Add(count);
                    }
                }
                if (BlockHashed != null)
                    BlockHashed(this, new BlockFinishedEventArgs(count));
            }
            int MaxExistBlockIndex;//已存在的区块最大序号
            try
            {
                MaxExistBlockIndex = _ExistBlock.Max();
            }
            catch
            {
                MaxExistBlockIndex = 0;
            }
            List<int> BlockRemaining = new List<int>();
            for (int index = 0; index < _TotalBlock; )
            {//计算仍需传输的区块
                if (index <= MaxExistBlockIndex)
                {
                    if (_ExistBlock.Exists(a => a == index))
                    {
                        index++;
                        continue;
                    }
                }
                BlockRemaining.Add(index++);
            }
            return BlockRemaining;
        }
        /// <summary>
        /// 接收整个文件
        /// </summary>
        internal void DownLoad()
        {
            try
            {
                if (string.IsNullOrEmpty(FilePath))//未指定路径时默认为接收程序所在路径
                    FilePath = Environment.CurrentDirectory;
                if (string.IsNullOrEmpty(FileName))//未指定文件名时从发送端获取
                {
                    GetFileName();
                }
                _FileStream = new FileStream(FullFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);//temp
                GetTotalBlock();
                GetLastBlockSize();
                List<int> BlockRemaining = HashFile();
                if (_FileStream.Length > TotalSize)//如果已存在的文件比目标文件长则截断它
                    _FileStream.SetLength(TotalSize);
                _StartTime = DateTime.Now;
                foreach (int index in BlockRemaining)
                {
                    FileBlock Block;
                    while (true)
                    {
                        SendString(string.Format("GET FileBlock {0}", index));
                        try
                        {
                            Block = ReceiveFileBlock();
                            break;
                        }
                        catch (FileBlockException)
                        {//接收到错误的区块,抛弃该数据并重新请求
                            _CastBlock.Add(index);
                        }
                        catch (Exception ex)
                        {
                            OnErrorOccurred(ex);
                        }
                    }
                    while (true)
                    {
                        try
                        {
                            _Blocks[index] = Block;//写入区块
                            OnBlockFinished(index);
                            break;
                        }
                        catch (IOException ex)
                        {//磁盘写入错误时
                            try
                            {
                                OnErrorOccurred(ex);
                                //重试
                            }
                            catch
                            {//退出
                                Stop();
                                return;
                            }
                        }
                        catch (Exception ex)
                        {
                            OnErrorOccurred(ex);
                        }
                    }
                }
                SendStringAsync("Exit");
                _Blocks.WriteAllBlock();
                OnAllFinished();
                Stop();
            }
            catch (SocketException) { }
            catch (Exception ex)
            {
                OnErrorOccurred(ex);
            }
        }
    }
    #endregion
}

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. argument to nsmutablearray method addobject cannot be nil 警告

    You cannot add nil to an NSMutableArray, and you will raise an exception if you try to. There's NSNu ...

  2. BUPT复试专题—哈夫曼树(2010)

    https://www.nowcoder.com/practice/162753046d5f47c7aac01a5b2fcda155?tpId=67&tqId=29635&tPage= ...

  3. COCOS学习笔记--重力感应Acceleration

    Cocos2dx重力感应Acceleration,准确来说叫加速度计,加速度计能够感应设备上X.Y.Z轴方向上线性加速度的变化.事实上叫"重力感应"或"重力加速度计&qu ...

  4. 利用反射技术实现POJO的数据库操作

    记得第一次写项目的时候,傻傻的数据库一张表,代码里就写一个DAO类,几张表就写几个DAO类,大量的反复代码,自己粘着都嫌烦,后来接触了Hibernate,不得不说对我们这样的小白用处还是非常大的.那么 ...

  5. Android 最新控件 Toolbar

    之前Android的ActionBar好像做项目从没用过.除了google自己,并没有多少人用,究其原因,主要是由于ActionBar不够灵活,不可以随心所欲的定制,后来Goole也发现了这一点,然后 ...

  6. 在linux中安装.sh 文件

    有一些linux的安装包是.sh后缀的安装包,可以通过$bash xxx.sh的命令来进行安装.

  7. C# json反序列化 对象中嵌套数组 (转载) 可能会导致循环或多重级联路径。请指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。

    C# json反序列化 对象中嵌套数组 (转载)   看图: 这里可以看到是二层嵌套!!使用C#如何实现?? 思路:使用list集合实现 → 建立类 → list集合 → 微软的   Newtonso ...

  8. OpenCV中使用SVM简介

    下面这是opencv官方文档中的代码,我加了一部分注释: #include "stdafx.h" #include "opencv2/core/core.hpp" ...

  9. 【前端JS】radio 可单选可点击取消选中

    普通情况下 radio 单选框仅仅能实现多选一的效果,可是一旦选择当中一个后,这个单选框就不可点击取消其选中状态了.这样的功能在某些业务环境下并不适用.有时我们既须要单选框的多选一效果.也须要复选框的 ...

  10. I want a mysqldump –ignore-database option

    $ time mysqldump --databases `mysql --skip-column-names -e "SELECT GROUP_CONCAT(schema_name SEP ...