zoukankan      html  css  js  c++  java
  • C#: 实现支持断点续传多线程下载

    /* .Net/C#: 实现支持断点续传多线程下载的 Http Web 客户端工具类 (C# DIY HttpWebClient)
    * Reflector 了一下 System.Net.WebClient ,改写或增加了若干:
    * DownLoadUpload 相关方法!
    * DownLoad 相关改动较大!
    增加了 DataReceiveExceptionOccurrs 事件!
    了解服务器端与客户端交互的 HTTP 协议参阅:
    使文件下载的自定义连接支持 FlashGet 的断点续传多线程链接下载! JSP/Servlet 实现!
    * http://blog.csdn.net/playyuer/archive/2004/08/02/58430.aspx
    使文件下载的自定义连接支持 FlashGet 的断点续传多线程链接下载! C#/ASP.Net 实现!
    * http://blog.csdn.net/playyuer/archive/2004/08/02/58281.aspx
    */
    //2005-03-14 修订:
    /* .Net/C#: 实现支持断点续传多线程下载的工具类
    * Reflector 了一下 System.Net.WebClient ,改写或增加了若干:
    * DownLoadUpload 相关方法!
    增加了 DataReceiveExceptionOccurrs 事件
    */
    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 FileNamestring AttachmentName,int Positionint Lengthbyte[] 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 FileNamestring AttachmentName,int Positionint 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 FileNamestring AttachmentName,int Positionint 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 Sstring s, int Iint 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 Addressstring FileNameint ChunksCount)
    {
    int 0; // position
    int 0; // chunk size
    string = null;
    HttpWebRequest hwrq;
    HttpWebResponse hwrp = null;
    try
    {
    hwrq = (HttpWebRequestWebRequest.Create(this.GetUri(Address));
    hwrp = (HttpWebResponsehwrq.GetResponse();
    long L = hwrp.ContentLength;
    hwrq.Credentials this.m_credentials;
    L = ((L == -1) || (L > 0x7fffffff)) ? ((long0x7fffffff) : L//Int32.MaxValue 该常数的值为 2,147,483,647; 即十六进制的 0x7FFFFFFF
    int = (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 = (hwrp.Headers["Accept-Ranges"] != null & hwrp.Headers["Accept-Ranges"] == "bytes");
    hwrp.Headers["Content-Disposition"]//attachment
    if (!= null)
    {
    a.Substring(a.LastIndexOf("filename=") + 9);
    }
    else
    {
    FileName;
    }
    int ss s;
    if (b)
    {
    ChunksCount;
    if (64 1024//块大小至少为 128 K 字节
    {
    64 1024;
    }
    ss s;
    int 0;
    while (s)
    {
    -= s;
    if (s)
    {
    += l;
    }
    if (i++ > 0)
    {
    DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePathFileName, a, p, s, newThreadCallbackHandler(this.DownloadFileChunk));
    // 单线程下载
    // x.StartDownloadFileChunk();
    x.httpWebClient this;
    //多线程下载
    Thread = new Thread(new ThreadStart(x.StartDownloadFileChunk));
    //this.OnThreadProcess(t);
    t.Start();
    }
    += 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.AbsolutePathFileName, a, p, s);
    ExceptionEventArgs eea = new ExceptionEventArgs(e, x);
    ExceptionOccurrs(this, eea);
    ea eea.ExceptionAction;
    }
    if (ea == ExceptionActions.Throw)
    {
    if (!(is WebException) && !(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 Addressstring FileNameint FromPosition, int Length)
    {
    HttpWebResponse hwrp = null;
    string = null;
    try
    {
    //this._FileName = FileName;
    HttpWebRequest hwrq = (HttpWebRequestWebRequest.Create(this.GetUri(Address));
    //hwrq.Credentials = this.m_credentials;
    hwrq.AddRange(FromPosition);
    hwrp = (HttpWebResponsehwrq.GetResponse();
    hwrp.Headers["Content-Disposition"]//attachment
    if (!= null)
    {
    a.Substring(a.LastIndexOf("filename=") + 9);
    }
    else
    {
    FileName;
    }
    byte[] buffer this.ResponseAsBytes(Address, hwrp, LengthFileName);
    // lock (_SyncLockObject)
    // {
    // this._Bytes += buffer.Length;
    // }
    }
    catch (Exception e)
    {
    ExceptionActions ea ExceptionActions.Throw;
    if (this.ExceptionOccurrs != null)
    {
    DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePathFileName, a, FromPosition, Length);
    ExceptionEventArgs eea = new ExceptionEventArgs(e, x);
    ExceptionOccurrs(this, eea);
    ea eea.ExceptionAction;
    }
    if (ea == ExceptionActions.Throw)
    {
    if (!(is WebException) && !(is SecurityException))
    {
    throw new WebException("net_webclient", e);
    }
    throw;
    }
    }
    }
    internal byte[] ResponseAsBytes(string RequestURL, WebResponse Responselong LengthstringFileName)
    {
    string = null//AttachmentName
    int P = 0; //整个文件的位置指针
    int num2 0;
    try
    {
    Response.Headers["Content-Disposition"]//attachment
    if (!= null)
    {
    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[(intnum1];
    int 0; //本块的位置指针
    string Response.Headers["Content-Range"];
    if (!= null)
    {
    s.Replace("bytes """);
    s.Substring(0, s.IndexOf("-"));
    P = Convert.ToInt32(s);
    }
    int num3 0;
    Stream S = Response.GetResponseStream();
    do
    {
    num2 = S.Read(buffer1, num3, ((intnum1) - num3);
    num3 += num2;
    if (flag1 && (num3 == num1))
    {
    num1 += 0x10000;
    byte[] buffer2 = new byte[(intnum1];
    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.AbsolutePathFileName, a,P, num2, buffer);
    DownLoadEventArgs dlea = new DownLoadEventArgs(dls);
    //触发事件
    this.OnDataReceive(dlea);
    //System.Threading.Thread.Sleep(100);
    }
    += 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.AbsolutePathFileName, a,P, num2);
    ExceptionEventArgs eea = new ExceptionEventArgs(e, x);
    ExceptionOccurrs(this, eea);
    ea eea.ExceptionAction;
    }
    if (ea == ExceptionActions.Throw)
    {
    if (!(is WebException) && !(is SecurityException))
    {
    throw new WebException("net_webclient", e);
    }
    throw;
    }
    return null;
    }
    }
    private void OnDataReceive(DownLoadEventArgs e)
    {
    //触发数据到达事件
    DataReceive(this, e);
    }
    public byte[] UploadFile(string address, string fileName)
    {
    return this.UploadFile(address, "POST", fileName, "file");
    }
    public string UploadFileEx(string address, string method, string fileName, string fieldName)
    {
    return Encoding.ASCII.GetString(UploadFile(address, method, fileName, fieldName));
    }
    public byte[] UploadFile(string address, string method, string fileName, string fieldName)
    {
    byte[] buffer4;
    FileStream stream1 = null;
    try
    {
    fileName Path.GetFullPath(fileName);
    string text1 "---------------------" DateTime.Now.Ticks.ToString("x");
    string text2 "application/octet-stream";
    stream1 = new FileStream(fileName, FileMode.OpenFileAccess.Read);
    WebRequest request1 WebRequest.Create(this.GetUri(address));
    request1.Credentials this.m_credentials;
    request1.ContentType "multipart/form-data; boundary=" text1;
    request1.Method method;
    string[] textArray1 = new string[7] {"--", text1, " Content-Disposition: form-data; name="" +fieldName ""; filename=""Path.GetFileName(fileName)"" Content-Type: ", text2, " "};
    string text3 string.Concat(textArray1);
    byte[] buffer1 Encoding.UTF8.GetBytes(text3);
    byte[] buffer2 Encoding.ASCII.GetBytes(" --" text1 " ");
    long num1 0x7fffffffffffffff;
    try
    {
    num1 stream1.Length;
    request1.ContentLength = (num1 buffer1.Length) + buffer2.Length;
    }
    catch
    {
    }
    byte[] buffer3 = new byte[Math.Min(0x2000, (intnum1)];
    using (Stream stream2 request1.GetRequestStream())
    {
    int num2;
    stream2.Write(buffer1, 0, buffer1.Length);
    do
    {
    num2 stream1.Read(buffer3, 0, buffer3.Length);
    if (num2 != 0)
    {
    stream2.Write(buffer3, 0, num2);
    }
    }
    while (num2 != 0);
    stream2.Write(buffer2, 0, buffer2.Length);
    }
    stream1.Close();
    stream1 = null;
    WebResponse response1 request1.GetResponse();
    buffer4 this.ResponseAsBytes(response1);
    }
    catch (Exception exception1)
    {
    if (stream1 != null)
    {
    stream1.Close();
    stream1 = null;
    }
    if (!(exception1 is WebException) && !(exception1 is SecurityException))
    {
    //throw new WebException(SR.GetString("net_webclient"), exception1);
    throw new WebException("net_webclient", exception1);
    }
    throw;
    }
    return buffer4;
    }
    private byte[] ResponseAsBytes(WebResponse response)
    {
    int num2;
    long num1 response.ContentLength;
    bool flag1 false;
    if (num1 == -1)
    {
    flag1 true;
    num1 0x10000;
    }
    byte[] buffer1 = new byte[(intnum1];
    Stream stream1 response.GetResponseStream();
    int num3 0;
    do
    {
    num2 stream1.Read(buffer1, num3, ((intnum1) - num3);
    num3 += num2;
    if (flag1 && (num3 == num1))
    {
    num1 += 0x10000;
    byte[] buffer2 = new byte[(intnum1];
    Buffer.BlockCopy(buffer1, 0, buffer2, 0, num3);
    buffer1 buffer2;
    }
    }
    while (num2 != 0);
    stream1.Close();
    if (flag1)
    {
    byte[] buffer3 = new byte[num3];
    Buffer.BlockCopy(buffer1, 0, buffer3, 0, num3);
    buffer1 buffer3;
    }
    return buffer1;
    }
    private NameValueCollection m_requestParameters;
    private Uri m_baseAddress;
    private ICredentials m_credentials CredentialCache.DefaultCredentials;
    public ICredentials Credentials
    {
    get
    {
    return this.m_credentials;
    }
    set
    {
    this.m_credentials = value;
    }
    }
    public NameValueCollection QueryString
    {
    get
    {
    if (this.m_requestParameters == null)
    {
    this.m_requestParameters = new NameValueCollection();
    }
    return this.m_requestParameters;
    }
    set
    {
    this.m_requestParameters = value;
    }
    }
    public string BaseAddress
    {
    get
    {
    if (this.m_baseAddress != null)
    {
    return this.m_baseAddress.ToString();
    }
    return string.Empty;
    }
    set
    {
    if ((value == null) || (value.Length == 0))
    {
    this.m_baseAddress = null;
    }
    else
    {
    try
    {
    this.m_baseAddress = new Uri(value);
    }
    catch (Exception exception1)
    {
    throw new ArgumentException("value", exception1);
    }
    }
    }
    }
    private Uri GetUri(string path)
    {
    Uri uri1;
    try
    {
    if (this.m_baseAddress != null)
    {
    uri1 = new Uri(this.m_baseAddress, path);
    }
    else
    {
    uri1 = new Uri(path);
    }
    if (this.m_requestParameters == null)
    {
    return uri1;
    }
    StringBuilder builder1 = new StringBuilder();
    string text1 string.Empty;
    for (int num1 0; num1 this.m_requestParameters.Count; num1++)
    {
    builder1.Append(text1 this.m_requestParameters.AllKeys[num1] + "=" +this.m_requestParameters[num1]);
    text1 "&";
    }
    UriBuilder builder2 = new UriBuilder(uri1);
    builder2.Query builder1.ToString();
    uri1 builder2.Uri;
    }
    catch (UriFormatException)
    {
    uri1 = new Uri(Path.GetFullPath(path));
    }
    return uri1;
    }
    }
    }
    /// <summary>
    /// 测试类
    /// </summary>
    class AppTest
    {
    int _k 0;
    int _K 0;
    static void Main()
    {
    AppTest a = new AppTest();
    Microshaoft.Utils.HttpWebClient x = new Microshaoft.Utils.HttpWebClient();
    a._K 10;
    //订阅 DataReceive 事件
    x.DataReceive += new Microshaoft.Utils.HttpWebClient.DataReceiveEventHandler(a.x_DataReceive);
    //订阅 ExceptionOccurrs 事件
    x.ExceptionOccurrs += newMicroshaoft.Utils.HttpWebClient.ExceptionEventHandler(a.x_ExceptionOccurrs);
    x.ThreadProcessEnd += newMicroshaoft.Utils.HttpWebClient.ThreadProcessEventHandler(a.x_ThreadProcessEnd);
    string F = "http://localhost/download/phpMyAdmin-2.6.1-pl2.zip";
    F = "http://down6.flashget.com/flashget182cn.exe";
    a._F = F;
    string = F.Substring(F.LastIndexOf("/") + 1);
    //(new System.Threading.Thread(new System.Threading.ThreadStart(new ThreadProcessState(F, @"E: emp" + f, 10, x).StartThreadProcess))).Start();
    x.DownloadFile(F, @"d: emp" + f, a._K);
    // x.DownloadFileChunk(F, @"E: emp" + f,15,34556);
    System.Console.ReadLine();
    // string uploadfile = "e:\test_local.rar";
    // string str = x.UploadFileEx("http://localhost/phpmyadmin/uploadaction.php", "POST", uploadfile, "file1");
    // System.Console.WriteLine(str);
    // System.Console.ReadLine();
    }
    string bs ""//用于记录上次的位数
    bool false;
    private int 0;
    private static object _SyncLockObject = new object();
    string _F;
    string _f;
    private void x_DataReceive(Microshaoft.Utils.HttpWebClient Sender, Microshaoft.Utils.DownLoadEventArgs e)
    {
    if (!this.b)
    {
    lock (_SyncLockObject)
    {
    if (!this.b)
    {
    System.Console.Write(System.DateTime.Now.ToString() + 已接收数据: ");
    //System.Console.Write( System.DateTime.Now.ToString() + " 已接收数据: ");
    this.true;
    }
    }
    }
    string e.DownloadState.FileName;
    if (e.DownloadState.AttachmentName != null)
    System.IO.Path.GetDirectoryName(f) + @"" + e.DownloadState.AttachmentName;
    this._f f;
    using (System.IO.FileStream sw = new System.IO.FileStream(f, System.IO.FileMode.OpenOrCreate,System.IO.FileAccess.ReadWriteSystem.IO.FileShare.ReadWrite))
    {
    sw.Position e.DownloadState.Position;
    sw.Write(e.DownloadState.Data, 0, e.DownloadState.Data.Length);
    sw.Close();
    }
    string System.DateTime.Now.ToString();
    lock (_SyncLockObject)
    {
    this.+= e.DownloadState.Data.Length;
    System.Console.Write(bs """ / " Sender.FileLength 字节数据 " s);
    //System.Console.Write(bs + i + " 字节数据 " + s);
    this.bs = new string('', Digits(i) + Digits(Sender.FileLength) + s.Length);
    }
    }
    int Digits(int n//数字所占位数
    {
    System.Math.Abs(n);
    10;
    int 1;
    while (0)
    {
    10;
    i++;
    }
    return i;
    }
    private void x_ExceptionOccurrs(Microshaoft.Utils.HttpWebClient Sender, Microshaoft.Utils.ExceptionEventArgs e)
    {
    System.Console.WriteLine(e.Exception.Message);
    //发生异常重新下载相当于断点续传,你可以自己自行选择处理方式
    Microshaoft.Utils.HttpWebClient x = new Microshaoft.Utils.HttpWebClient();
    x.DownloadFileChunk(this._F, this._f, e.DownloadState.Position, e.DownloadState.Length);
    e.ExceptionAction Microshaoft.Utils.ExceptionActions.Ignore;
    }
    private void x_ThreadProcessEnd(Microshaoft.Utils.HttpWebClient Sender, Microshaoft.Utils.ThreadProcessEventArgs e)
    {
    //if (e.thread.ThreadState == System.Threading.ThreadState.Stopped)
    if (this._k ++ == this._K 1)
    System.Console.WriteLine(" end");
    }
    }

  • 相关阅读:
    进程与线程
    the art of seo(chapter seven)
    the art of seo(chapter six)
    the art of seo(chapter five)
    the art of seo(chapter four)
    the art of seo(chapter three)
    the art of seo(chapter two)
    the art of seo(chapter one)
    Sentinel Cluster流程分析
    Sentinel Core流程分析
  • 原文地址:https://www.cnblogs.com/gc2013/p/3656972.html
Copyright © 2011-2022 走看看