架構設計
- 伺服端:極簡,僅監聽、接受連線、依請求發送檔案區塊
- 客戶端:核心邏輯集中,負責分塊、多執行緒下載、進度記錄、斷點續傳
自定義簡易協議
struct FileInfo {
int fileNo; // 檔案索引
int type; // 0=查詢列表, 2=請求傳輸
long len; // 區塊長度
int seek; // 起始位移
char name[100];
};
伺服端核心
// 監聽執行緒
DWORD WINAPI ListenThread(LPVOID p) {
SOCKET s = (SOCKET)p;
listen(s, 30);
while (true) {
SOCKET c = accept(s, nullptr, nullptr);
CreateThread(nullptr, 0, ClientThread, (LPVOID)c, 0, nullptr);
}
}
// 客戶執行緒
DWORD WINAPI ClientThread(LPVOID p) {
SOCKET c = (SOCKET)p;
FileInfo fi; recv(c, (char*)&fi, sizeof(fi), 0);
if (fi.type == 0) send(c, (char*)fileList, listSize, 0); // 回傳列表
else if (fi.type == 2) SendFileBlock(c, fi.seek, fi.len, fi.fileNo);
}
客戶端 CDownload 類別
class CDownload {
FileInfo m_info;
int m_range[200]; // [seek0, len0, seek1, len1...]
BOOL m_done[100];
CString m_fileName, m_tempName;
public:
int StartTask(int fileNo); // 初始化、分塊、建立進度檔
void CreateThreads(); // 啟動 N 條下載執行緒
UINT ThreadFunc(int index); // 單執行緒下載迴圈
DWORD FinishCheck(); // 檢查完成、合併、清理
};
斷點續傳關鍵:進度檔持久化
- 首次下載:建立
.down 總進度檔 + .down0~.downN 分塊進度檔
- 每次寫入磁碟前更新對應
.downN:seek、len 即時刷新
- 啟動時讀取所有
.downN 計算已下載總量,跳過完成分塊
- 全部
m_done[]=TRUE 後刪除進度檔,標記完成
多執行緒同步
// 執行緒索引原子遞增
InterlockedIncrement(&m_index);
UINT idx = m_index - 1;
ThreadFunc(idx);
效果展示
