首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

自實現 HTTP 下載引擎:Socket 級別格式化 Request/Response、斷點續傳、DLL 封裝

     編輯:關於VC++

專案動機

WinInet/URLMon 雖方便,但難以精細控制:斷點續傳、自定 Header、超時策略、代理認證等。本文實作一個 CHttpSocket 類別,直接操作 TCP Socket 實現 HTTP/1.1 下載,封裝為 DLL 供上層呼叫。

HTTP Request 組裝


GET /index.html HTTP/1.1\r\n
Host: www.example.com\r\n
Accept: */*\r\n
User-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)\r\n
Connection: Keep-Alive\r\n
Range: bytes=999-\r\n        ← 斷點續傳關鍵:從第 1000 字節開始
\r\n                                   ← 必須以空行結束

CHttpSocket 核心介面


class CHttpSocket {
public:
    // 連線管理
    BOOL Socket(int nType = SOCK_STREAM);
    BOOL Connect(LPCTSTR pszHost, UINT nPort = 80);
    void Close();

    // Request 組裝與發送
    const char* FormatRequestHeader(
        char* pServer, char* pObject, long& nLength,
        char* pCookie = NULL, char* pReferer = NULL,
        long nFrom = 0, long nTo = -1, int nServerType = 0);
    BOOL SendRequest(const char* pRequest, long nLength);

    // Response 解析
    int GetServerState();                    // 200, 302, 404...
    int GetField(const char* szField, char* szValue, int nMaxLen); // 取單一欄位
    const char* GetResponseHeader(int& nLength); // 取完整 Header

    // 資料接收
    int Receive(void* pBuf, int nLen, int nFlags = 0);

    // 超時設定
    void SetSendTimeout(int nMs);
    void SetRecvTimeout(int nMs);
};

Request 組裝關鍵代碼


const char* CHttpSocket::FormatRequestHeader(...) {
    // 第1行
    strcat(m_req, "GET "); strcat(m_req, pObject); strcat(m_req, " HTTP/1.1\r\n");
    // Host
    strcat(m_req, "Host: "); strcat(m_req, pServer); strcat(m_req, "\r\n");
    // Referer (可選)
    if (pReferer) { strcat(m_req, "Referer: "); strcat(m_req, pReferer); strcat(m_req, "\r\n"); }
    // Accept
    strcat(m_req, "Accept: */*\r\n");
    // User-Agent
    strcat(m_req, "User-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)\r\n");
    // Connection
    strcat(m_req, "Connection: Keep-Alive\r\n");
    // Cookie (可選)
    if (pCookie) { strcat(m_req, "Cookie: "); strcat(m_req, pCookie); strcat(m_req, "\r\n"); }
    // Range (斷點續傳)
    if (nFrom > 0) {
        strcat(m_req, "Range: bytes=");
        char sz[20]; _ltoa(nFrom, sz, 10); strcat(m_req, sz); strcat(m_req, "-");
        if (nTo > nFrom) { _ltoa(nTo, sz, 10); strcat(m_req, sz); }
        strcat(m_req, "\r\n");
    }
    // 空行結束
    strcat(m_req, "\r\n");
    nLength = strlen(m_req);
    return m_req;
}

Response 解析重點

  • 狀態行:HTTP/1.1 200 OK → GetServerState() 回傳 200
  • 關鍵欄位:
    • Content-Length:檔案總大小 (若無則可能為 Chunked 編碼)
    • Location:3xx 重導向新網址
    • Accept-Ranges: bytes:伺服器支援斷點續傳
    • Last-Modified:檔案修改時間,供快取驗證
  • Header 以雙 \r\n 結束,其後為實體內容

完整下載流程

  1. AfxParseURL() 解析 URL → 主機/埠/路徑
  2. Socket() → Connect()
  3. FormatRequestHeader() 組裝 Request (含 Range 斷點)
  4. SendRequest() 發送
  5. GetServerState() 檢查 2xx
  6. GetField("Content-Length") 取得檔案大小
  7. 迴圈 Receive() 寫入檔案,直到收滿 Content-Length 或連線關閉

執行介面展示

下載工具介面:顯示 Request/Response Header 與進度

多執行緒與非阻塞建議

  • 所有介面均為同步阻塞,UI 執行緒直接呼叫會凍結介面
  • 必須為每個下載任務建立獨立工作者執行緒 (AfxBeginThread)
  • 進度回報:PostMessage(WM_USER_PROGRESS, ...) 至 UI 執行緒
  • 取消支援:執行緒檢查旗標,呼叫 Close() 關閉 Socket

擴充方向

  • HTTPS 支援:整合 OpenSSL / Schannel
  • Chunked Transfer Encoding 解析
  • Proxy (HTTP/SOCKS4/5) 支援
  • 多執行緒分段下載 (多 Range 並行)
  • Cookie 持久化 (RFC 6265)

完整原始碼 (含 DLL 專案與測試對話框) 請參考本文配套下載。此實作為理解 HTTP 協議、Socket 程式設計、斷點續傳機制的優秀教學範例。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved