HTTP多线路断点续传

    技术2022-05-20  27

    namespace Microshaoft.Utils{    using System;    using System.IO;    using System.Net;    using System.Text;    using System.Security;    using System.Threading;    using System.Collections.Specialized;    /// <summary>     /// 记录下载的字节位置     /// </summary>     public class DownLoadState    {        private string _FileName;        private string _AttachmentName;        private int _Position;        private string _RequestURL;        private string _ResponseURL;        private int _Length;        private byte[] _Data;        public string FileName        {            get            {                return _FileName;            }        }        public int Position        {            get            {                return _Position;            }        }        public int Length        {            get            {                return _Length;            }        }        public string AttachmentName        {            get            {                return _AttachmentName;            }        }        public string RequestURL        {            get            {                return _RequestURL;            }        }        public string ResponseURL        {            get            {                return _ResponseURL;            }        }        public byte[] Data        {            get            {                return _Data;            }        }        internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length, byte[] Data)        {            this._FileName = FileName;            this._RequestURL = RequestURL;            this._ResponseURL = ResponseURL;            this._AttachmentName = AttachmentName;            this._Position = Position;            this._Data = Data;            this._Length = Length;        }        internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length, ThreadCallbackHandler tch)        {            this._RequestURL = RequestURL;            this._ResponseURL = ResponseURL;            this._FileName = FileName;            this._AttachmentName = AttachmentName;            this._Position = Position;            this._Length = Length;            this._ThreadCallback = tch;        }        internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length)        {            this._RequestURL = RequestURL;            this._ResponseURL = ResponseURL;            this._FileName = FileName;            this._AttachmentName = AttachmentName;            this._Position = Position;            this._Length = Length;        }        private ThreadCallbackHandler _ThreadCallback;        public HttpWebClient httpWebClient        {            get            {                return this._hwc;            }            set            {                this._hwc = value;            }        }        internal Thread thread        {            get            {                return _thread;            }            set            {                _thread = value;            }        }        private HttpWebClient _hwc;        private Thread _thread;        //         internal void StartDownloadFileChunk()        {            if (this._ThreadCallback != null)            {                this._ThreadCallback(this._RequestURL, this._FileName, this._Position, this._Length);                this._hwc.OnThreadProcess(this._thread);            }        }    }    //委托代理线程的所执行的方法签名一致     public delegate void ThreadCallbackHandler(string S, string s, int I, int i);    //异常处理动作     public enum ExceptionActions    {        Throw,        CancelAll,        Ignore,        Retry    }    /// <summary>     /// 包含 Exception 事件数据的类     /// </summary>     public class ExceptionEventArgs : System.EventArgs    {        private System.Exception _Exception;        private ExceptionActions _ExceptionAction;        private DownLoadState _DownloadState;        public DownLoadState DownloadState        {            get            {                return _DownloadState;            }        }        public Exception Exception        {            get            {                return _Exception;            }        }        public ExceptionActions ExceptionAction        {            get            {                return _ExceptionAction;            }            set            {                _ExceptionAction = value;            }        }        internal ExceptionEventArgs(System.Exception e, DownLoadState DownloadState)        {            this._Exception = e;            this._DownloadState = DownloadState;        }    }    /// <summary>     /// 包含 DownLoad 事件数据的类     /// </summary>     public class DownLoadEventArgs : System.EventArgs    {        private DownLoadState _DownloadState;        public DownLoadState DownloadState        {            get            {                return _DownloadState;            }        }        public DownLoadEventArgs(DownLoadState DownloadState)        {            this._DownloadState = DownloadState;        }    }    public class ThreadProcessEventArgs : System.EventArgs    {        private Thread _thread;        public Thread thread        {            get            {                return this._thread;            }        }        public ThreadProcessEventArgs(Thread thread)        {            this._thread = thread;        }    }    /// <summary>     /// 支持断点续传多线程下载的类     /// </summary>     public class HttpWebClient    {        private static object _SyncLockObject = new object();        public delegate void DataReceiveEventHandler(HttpWebClient Sender, DownLoadEventArgs e);        public event DataReceiveEventHandler DataReceive; //接收字节数据事件        public delegate void ExceptionEventHandler(HttpWebClient Sender, ExceptionEventArgs e);        public event ExceptionEventHandler ExceptionOccurrs; //发生异常事件        public delegate void ThreadProcessEventHandler(HttpWebClient Sender, ThreadProcessEventArgs e);        public event ThreadProcessEventHandler ThreadProcessEnd; //发生多线程处理完毕事件        private int _FileLength; //下载文件的总大小         public int FileLength        {            get            {                return _FileLength;            }        }        /// <summary>         /// 分块下载文件         /// </summary>         /// <param name="Address">URL 地址</param>         /// <param name="FileName">保存到本地的路径文件名</param>         /// <param name="ChunksCount">块数,线程数</param>         public void DownloadFile(string Address, string FileName, int ChunksCount)        {            int p = 0; // position             int s = 0; // chunk size             string a = null;            HttpWebRequest hwrq;            HttpWebResponse hwrp = null;            try            {                hwrq = (HttpWebRequest)WebRequest.Create(this.GetUri(Address));                hwrp = (HttpWebResponse)hwrq.GetResponse();                long L = hwrp.ContentLength;                hwrq.Credentials = this.m_credentials;                L = ((L == -1) || (L > 0x7fffffff)) ? ((long)0x7fffffff) : L; //Int32.MaxValue 该常数的值为 2,147,483,647; 即十六进制的 0x7FFFFFFF                int l = (int)L;                this._FileLength = l;                //    在本地预定空间(竟然在多线程下不用先预定空间)                 //    FileStream sw = new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);                 //    sw.Write(new byte[l], 0, l);                 //    sw.Close();                 //    sw = null;                 bool b = (hwrp.Headers["Accept-Ranges"] != null & hwrp.Headers["Accept-Ranges"] == "bytes");                a = hwrp.Headers["Content-Disposition"]; //attachment                 if (a != null)                {                    a = a.Substring(a.LastIndexOf("filename=") + 9);                }                else                {                    a = FileName;                }                int ss = s;                if (b)                {                    s = l / ChunksCount;                    if (s < 2 * 64 * 1024) //块大小至少为 128 K 字节                     {                        s = 2 * 64 * 1024;                    }                    ss = s;                    int i = 0;                    while (l > s)                    {                        l -= s;                        if (l < s)                        {                            s += l;                        }                        if (i++ > 0)                        {                            DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, p, s, new ThreadCallbackHandler(this.DownloadFileChunk));                            //       单线程下载                             //       x.StartDownloadFileChunk();                             x.httpWebClient = this;                            //多线程下载                             Thread t = new Thread(new ThreadStart(x.StartDownloadFileChunk));                            //this.OnThreadProcess(t);                             t.Start();                        }                        p += s;                    }                    s = ss;                    byte[] buffer = this.ResponseAsBytes(Address, hwrp, s, FileName);                    this.OnThreadProcess(Thread.CurrentThread);                    //    lock (_SyncLockObject)                     //    {                     //     this._Bytes += buffer.Length;                     //    }                 }            }            catch (Exception e)            {                ExceptionActions ea = ExceptionActions.Throw;                if (this.ExceptionOccurrs != null)                {                    DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, p, s);                    ExceptionEventArgs eea = new ExceptionEventArgs(e, x);                    ExceptionOccurrs(this, eea);                    ea = eea.ExceptionAction;                }                if (ea == ExceptionActions.Throw)                {                    if (!(e is WebException) && !(e is SecurityException))                    {                        throw new WebException("net_webclient", e);                    }                    throw;                }            }        }        internal void OnThreadProcess(Thread t)        {            if (ThreadProcessEnd != null)            {                ThreadProcessEventArgs tpea = new ThreadProcessEventArgs(t);                ThreadProcessEnd(this, tpea);            }        }        /// <summary>         /// 下载一个文件块,利用该方法可自行实现多线程断点续传         /// </summary>         /// <param name="Address">URL 地址</param>         /// <param name="FileName">保存到本地的路径文件名</param>         /// <param name="Length">块大小</param>         public void DownloadFileChunk(string Address, string FileName, int FromPosition, int Length)        {            HttpWebResponse hwrp = null;            string a = null;            try            {                //this._FileName = FileName;                 HttpWebRequest hwrq = (HttpWebRequest)WebRequest.Create(this.GetUri(Address));                //hwrq.Credentials = this.m_credentials;                 hwrq.AddRange(FromPosition);                hwrp = (HttpWebResponse)hwrq.GetResponse();                a = hwrp.Headers["Content-Disposition"]; //attachment                 if (a != null)                {                    a = a.Substring(a.LastIndexOf("filename=") + 9);                }                else                {                    a = FileName;                }                byte[] buffer = this.ResponseAsBytes(Address, hwrp, Length, FileName);                //   lock (_SyncLockObject)                 //   {                 //    this._Bytes += buffer.Length;                 //   }             }            catch (Exception e)            {                ExceptionActions ea = ExceptionActions.Throw;                if (this.ExceptionOccurrs != null)                {                    DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, FromPosition, Length);                    ExceptionEventArgs eea = new ExceptionEventArgs(e, x);                    ExceptionOccurrs(this, eea);                    ea = eea.ExceptionAction;                }                if (ea == ExceptionActions.Throw)                {                    if (!(e is WebException) && !(e is SecurityException))                    {                        throw new WebException("net_webclient", e);                    }                    throw;                }            }        }        internal byte[] ResponseAsBytes(string RequestURL, WebResponse Response, long Length, string FileName)        {            string a = null; //AttachmentName             int P = 0; //整个文件的位置指针             int num2 = 0;            try            {                a = Response.Headers["Content-Disposition"]; //attachment                 if (a != null)                {                    a = a.Substring(a.LastIndexOf("filename=") + 9);                }                long num1 = Length; //Response.ContentLength;                 bool flag1 = false;                if (num1 == -1)                {                    flag1 = true;                    num1 = 0x10000; //64k                 }                byte[] buffer1 = new byte[(int)num1];                int p = 0; //本块的位置指针                 string s = Response.Headers["Content-Range"];                if (s != null)                {                    s = s.Replace("bytes ", "");                    s = s.Substring(0, s.IndexOf("-"));                    P = Convert.ToInt32(s);                }                int num3 = 0;                Stream S = Response.GetResponseStream();                do                {                    num2 = S.Read(buffer1, num3, ((int)num1) - num3);                    num3 += num2;                    if (flag1 && (num3 == num1))                    {                        num1 += 0x10000;                        byte[] buffer2 = new byte[(int)num1];                        Buffer.BlockCopy(buffer1, 0, buffer2, 0, num3);                        buffer1 = buffer2;                    }                    //    lock (_SyncLockObject)                     //    {                     //     this._bytes += num2;                     //    }                     if (num2 > 0)                    {                        if (this.DataReceive != null)                        {                            byte[] buffer = new byte[num2];                            Buffer.BlockCopy(buffer1, p, buffer, 0, buffer.Length);                            DownLoadState dls = new DownLoadState(RequestURL, Response.ResponseUri.AbsolutePath, FileName, a, P, num2, buffer);                            DownLoadEventArgs dlea = new DownLoadEventArgs(dls);                            //触发事件                             this.OnDataReceive(dlea);                            //System.Threading.Thread.Sleep(100);                         }                        p += num2; //本块的位置指针                         P += num2; //整个文件的位置指针                     }                    else                    {                        break;                    }                }                while (num2 != 0);                S.Close();                S = null;                if (flag1)                {                    byte[] buffer3 = new byte[num3];                    Buffer.BlockCopy(buffer1, 0, buffer3, 0, num3);                    buffer1 = buffer3;                }                return buffer1;            }            catch (Exception e)            {                ExceptionActions ea = ExceptionActions.Throw;                if (this.ExceptionOccurrs != null)                {                    DownLoadState x = new DownLoadState(RequestURL, Response.ResponseUri.AbsolutePath, FileName, a, P, num2);                    ExceptionEventArgs eea = new ExceptionEventArgs(e, x);                    ExceptionOccurrs(this, eea);                    ea = eea.ExceptionAction;                }                if (ea == ExceptionActions.Throw)                {                    if (!(e is WebException) && !(e is SecurityException))                    {                        throw new WebException("net_webclient", e);                    }                    throw;                }                return null;            }        }


    最新回复(0)