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

VC++ 實作 FTP 多線程斷點續傳:基於 Socket 與 FTP 協定的完整解析

     編輯:VC 教學

前言:為什麼不用 WinInet?

雖然 Microsoft 提供的 WinInet API(InternetOpen、InternetConnect、FTPGetFile 等)能輕鬆實作基本 FTP 下載,但要達成多線程下載與斷點續傳,WinInet 的功能顯得力不從心。直接使用 Socket 依據 FTP 協定開發,雖然較繁瑣,卻能獲得最大彈性與控制權。本文將逐步解析完整開發流程,開發環境以 BCB 為例,VC++ 開發者可自行調整。

FTP 協定核心概念

雙通道架構

FTP 使用兩條連線:

  • 命令通道(預設連接埠 21):傳送 FTP 指令與回應。
  • 資料通道:實際傳輸檔案內容,可採用主動模式或被動模式建立。

常用 FTP 指令

指令說明
USER / PASS使用者帳號與密碼驗證
TYPE設定傳輸類型(ASCII / Binary),如 TYPE I 代表二進位模式
SIZE取得伺服器端檔案大小
REST設定檔案傳輸續傳位移點(斷點續傳關鍵)
CWD / PWD變更 / 查詢目前工作目錄
RETR下載檔案(從 REST 指定位移開始)
PASV進入被動模式,伺服器回傳 IP 與連接埠供客戶端連接資料通道
PORT主動模式,客戶端指定 IP 與連接埠供伺服器連接
QUIT結束連線

指令範例

USER sandy
PASS sandy
TYPE I
SIZE sandy.txt
REST 100
CWD infor/
PWD temp/
RETR sandy.txt
PASV
PORT 192,168,1,81,4,50  // IP: 192.168.1.81, Port: 4*256+50=1074

多線程下載流程設計

  1. 建立命令通道連線,發送 USER/PASS 登入。
  2. 使用 CWD/PWD 切換至目標目錄。
  3. 發送 SIZE 取得檔案總大小。
  4. 發送 REST 測試伺服器是否支援續傳(支援多線程必要條件)。
  5. 使用 PASV(推薦)或 PORT 建立資料通道。
  6. 將檔案分割為 N 個區塊,各線程負責一段(透過 REST + RETR 指定範圍)。
  7. 各線程獨立建立命令與資料通道進行下載。

斷點續傳檔案儲存策略

作者採用雙檔案法:

  • 內容檔(副檔名 .nam):預先配置與原檔同大小的空間(填 0),下載資料直接以 fseek 定位寫入對應位移。
  • 設定檔(副檔名 .san):記錄下載狀態,格式如下:
D:\download\namelock.avi      // 本地儲存路徑
364544                    // 檔案總大小
5                         // 線程數
0                         // 已下載總位元組數
0-72908                   // 線程1 任務範圍
72908-145816              // 線程2
145816-218724             // 線程3
218724-291632             // 線程4
291632-364544             // 線程5

下載過程中,各線程完成區塊後更新設定檔中的任務範圍與已下載總量。若某線程提前完成,會自動分擔最忙碌線程的剩餘任務(動態負載平衡),避免重複下載需注意緩衝區大小邊界。

多線程同步與效能優化

檔案存取同步

使用全域旗標 FileLocked 搭配 Sleep(10) 簡易互斥(生產環境建議使用 Critical Section 或 Mutex)。

設定檔記憶體映射

為避免頻繁讀寫設定檔,定義結構體在記憶體中維護狀態:

typedef struct FromToImpl {
    DWORD from;  // 任務起始位移
    DWORD to;    // 任務結束位移
} m_fromTo;

typedef struct InforImpl {
    CString fileLoad;        // 儲存路徑
    DWORD fileSize;          // 檔案大小
    int threadCnt;           // 線程數
    DWORD alreadyDownloadCnt;// 已下載總量
    FromToImpl *fromToImpl;  // 各線程任務陣列
} m_inforImpl;

下載期間常駐記憶體,僅於啟動時載入、結束時寫回,大幅提升效能。

關鍵程式碼片段:檔案分塊邏輯

bool DealFile(string fileName) {
    FILE *file = fopen(fileName.c_str(), "r+b");
    if (!file) return false;
    fseek(file, 0, SEEK_END);
    DWORD fileSize = ftell(file);
    fseek(file, 0, SEEK_SET);

    const int MAX_BUFFER_LEN = 8192;
    char *buffer = new char[MAX_BUFFER_LEN];
    DWORD pos = 0, readLen;

    do {
        readLen = fread(buffer, 1, MAX_BUFFER_LEN, file);
        if (readLen > 0) {
            pos += readLen;
            // 處理讀取資料(此處略)
        }
    } while (pos < fileSize);

    delete[] buffer;
    fclose(file);
    return true;
}

總結

本文完整揭露了基於 Socket 實作 FTP 多線程斷點續傳的核心技術:協定指令流程、雙檔案儲存策略、動態負載平衡、多線程同步與記憶體優化。這不僅能幫助理解 FlashGet 等下載工具的原理,對開發可重用網路元件也有極大參考價值。VC++ 開發者可參考邏輯移植至 MFC 或純 Win32 專案中。

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