WinInet API 雖簡單但難支援多執行緒下載。本文基於 FTP 協議與 Socket 實作多執行緒斷點續傳下載器,涵蓋協議指令、檔案分段策略、斷點資訊儲存、執行緒負載平衡等核心技術。
| 指令 | 用途 | 範例 |
|---|---|---|
| USER | 使用者名稱 | USER sandy |
| PASS | 密碼 | PASS 123456 |
| TYPE | 傳輸模式 | TYPE I (二進位) |
| SIZE | 取得檔案大小 | SIZE file.zip |
| REST | 設定續傳位移 | REST 102400 |
| CWD/PWD | 切換/查詢目錄 | CWD /pub/files |
| RETR | 下載檔案 (從 REST 位移開始) | RETR file.zip |
| PASV | 被動模式資料連線 | PASV → 回應 h1,h2,h3,h4,p1,p2 |
| PORT | 主動模式資料連線 | PORT h1,h2,h3,h4,p1,p2 |
| QUIT | 離開 | QUIT |
採雙檔案機制:
filename.nam (以女友英文名 namelock 取前三字) — 實際下載資料,預先配置完整大小並填 0filename.san (自身英文名 sandy 取前三字) — 記錄下載進度與執行緒任務分配下載完成後:內容檔改名為原檔名,設定檔刪除。
D:\download\movie.avi ; 本地儲存路徑
364544 ; 檔案總大小
5 ; 5 個下載執行緒
113868 ; 已下載位元組數
0-72908 ; 執行緒 1 任務範圍
72908-145816 ; 執行緒 2
145816-218724 ; 執行緒 3
218724-291632 ; 執行緒 4
291632-364544 ; 執行緒 5
struct TaskRange { DWORD from, to; }; // 單一執行緒任務範圍
struct DownloadInfo
{
CString localPath; // 本地路徑
DWORD fileSize; // 總大小
int threadCount; // 執行緒數
DWORD downloaded; // 已下載量
TaskRange* pTasks; // 各執行緒任務陣列
};
全域旗標 BOOL g_bFileLocked 保護設定檔/內容檔存取:
while (g_bFileLocked) Sleep(10);
g_bFileLocked = TRUE;
// 讀寫檔案...
g_bFileLocked = FALSE;
建議改用 CMutex 或 CRITICAL_SECTION 取代忙碌等待。
bool PrepareContentFile(const char* path, DWORD fileSize)
{
FILE* fp = fopen(path, "wb");
if (!fp) return false;
const int BUF_SIZE = 10000;
char* buf = new char[BUF_SIZE];
memset(buf, '0', BUF_SIZE);
DWORD written = 0;
while (written < fileSize)
{
int toWrite = min(BUF_SIZE, fileSize - written);
fwrite(buf, 1, toWrite, fp);
written += toWrite;
}
delete[] buf;
fclose(fp);
return true;
}
完整專案原始碼請下載附件。開發環境:BCB (元件模式),VC++ 需微調 Socket API 呼叫。
聯絡作者:wukangbin@funinhand.com