首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

C# 多執行緒斷點續傳下載元件 HttpWebClient 完整原始碼解析

     編輯:ASP.NET 基礎

設計目標

  • 支援多執行緒分塊下載,大幅提升速度。
  • 支援斷點續傳:網路中斷後可從上次位置繼續。
  • 事件驅動:`DataReceive` (進度)、`ExceptionOccurrs` (錯誤處理)、`ThreadProcessEnd` (執行緒結束)。
  • 相容 `HttpWebRequest`/`HttpWebResponse`,支援 `Range` 標頭。

核心類別結構

namespace Microshaoft.Utils
{
    public class DownLoadState      // 下載分塊狀態封裝
    public class ExceptionEventArgs // 例外事件參數,含 ExceptionAction (Throw/CancelAll/Ignore/Retry)
    public class DownLoadEventArgs  // 資料接收事件參數
    public class ThreadProcessEventArgs // 執行緒結束事件參數

    public class HttpWebClient
    {
        public event DataReceiveEventHandler DataReceive;
        public event ExceptionEventHandler ExceptionOccurrs;
        public event ThreadProcessEventHandler ThreadProcessEnd;

        public void DownloadFile(string url, string fileName, int chunks);      // 進入點
        public void DownloadFileChunk(string url, string fileName, int fromPos, int length); // 單塊下載
        // 內部:ResponseAsBytes、OnDataReceive、OnThreadProcess...
    }
}

關鍵流程:DownloadFile

  1. 發送 HEAD/GET 取得 `Content-Length` 與 `Accept-Ranges: bytes` 確認支援斷點。
  2. 計算每塊大小 (最小 128KB),建立多個 `DownLoadState`。
  3. 每塊啟動一條 `Thread` 執行 `DownloadFileChunk`。
  4. `DownloadFileChunk` 設定 `Request.AddRange(fromPos)`,讀取回應流,觸發 `DataReceive` 事件寫入檔案對應位置。
  5. 所有執行緒結束觸發 `ThreadProcessEnd`,呼叫端可判斷完成。

斷點續傳核心:Range 標頭

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.AddRange(fromPosition); // 關鍵:Range: bytes=fromPosition-

伺服器回應 `206 Partial Content`,`Content-Range` 標頭指示實際回傳範圍。

用戶端使用範例

var client = new HttpWebClient();
client.DataReceive += (s, e) => {
    using (var fs = new FileStream(e.DownloadState.FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
    {
        fs.Position = e.DownloadState.Position;
        fs.Write(e.DownloadState.Data, 0, e.DownloadState.Data.Length);
    }
    Console.Write($"已下載 {e.DownloadState.Position + e.DownloadState.Data.Length} / {client.FileLength}");
};
client.ExceptionOccurrs += (s, e) => {
    Console.WriteLine($"錯誤: {e.Exception.Message}, 重試中...");
    e.ExceptionAction = ExceptionActions.Retry; // 或 Ignore
    // 可在此重新呼叫 DownloadFileChunk 續傳
};
client.ThreadProcessEnd += (s, e) => { /* 計數完成 */ };

client.DownloadFile("https://example.com/large.zip", @"D:\temp\large.zip", 10); // 10 執行緒

注意事項與改進建議

  • 執行緒安全:檔案寫入使用 `FileShare.ReadWrite` 並 `Position` 定位,多執行緒並發寫入不同區塊安全。
  • 記憶體:`ResponseAsBytes` 會將整塊資料讀入記憶體再觸發事件,大檔案建議改用 `Stream` 邊讀邊寫。
  • 現代化替代:.NET Core / 5+ 建議使用 `HttpClient` + `HttpCompletionOption.ResponseHeadersRead` + `ReadAsStreamAsync` 實作非同步下載,搭配 `SemaphoreSlim` 控制並發。
  • 錯誤重試策略:`ExceptionActions.Retry` 需外部協調重試邏輯,建議內建指數退避重試。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved