本專案實作一個「遠程檔案管理 + 多線程下載」系統:伺服端採用 select 模型單線程處理大量連線;客戶端主線程負責 UI 與目錄樹互動,下載時動態建立多執行緒分段傳輸,支援斷點續傳邏輯。
select 執行緒輪詢 fd_set(預設 64 sockets),新連線 accept 加入集合,資料到達 recv 解析封包並回應。// 通訊封包
struct DATA_PACKET {
char packetType; // 'r':驅動器 'd':目錄 'f':檔案大小 'D':檔案資料
unsigned int length; // 依類型語意不同(下載時:高兩位=線程序號,低兩位=總線程數)
char content[2000]; // 路徑或資料
};
// 全域變數(線程間通訊)
char* pDrives; // 緩衝區
CString arrFiles[200]; // 目錄列表
CString savePath; // 儲存路徑
long fSize=0, recvFSize=0; // 檔案總大小/已收大小
CString strIP; // 伺服 IP
bool thrFlag=false; // 線程建立同步旗標
CAsyncSocket 跨線程傳遞參數極不便,改用純 Win32 socket/select/send/recv 靈活度高;檔案操作保留 CFile 或 fopen/fwrite。
直接 send 結構體含 CString 陣列會導致接收端指標失效。解法:將陣列序列化為單一 char*,以特殊字元 '|' 分隔(檔名不含此字元),接收端再解析還原。
迴圈 CreateThread 時,若主線程繼續跑,迴圈變數 j 可能已變更導致子線程拿到錯誤參數。
解法:while(CreateThread(...)==0) Sleep(30); 或用 thrFlag 置位機制——子線程啟動成功置 1,主線程等待歸零後再建下一個。
start = (idx-1)*len; end = (idx==total)? fSize : start+len;fseek 定位,寫入後 fflush 強制落盤。CCriticalSection 鎖住「定位+寫入+fflush」最小關鍵區,避免效能過度下降。fclose。while (i <= len && j <= 6) {
int k = 0;
while (pChar[i] != '|' && i <= len) { // 必須加 i<=len
strArray[j].Insert(k++, pChar[i++]);
}
i++; j++;
}
全域 char[2000] 二次 memcpy 若未重新分配,程式結束時會崩潰。解法:每次使用前 new char[2000] 或 memset 重置。
FD_ZERO/SET → select → FD_ISSET → accept/recv → 解析封包類型 → 回應計算區段 → 迴圈 recv+fseek+fwrite+fflush → 完成判斷 fclose連線 → send請求 → recv回應 → 分派處理(驅動器/目錄/檔案大小/檔案資料) → 呼叫 FillInFile自訂 CExtnTreeCtrl 繼承 CTreeCtrl,雙擊項目:
① 驅動器/資料夾 → 送 'd' 封包請求子項 → 回應填充樹節點。
② 檔案(有副檔名) → 送 'f' 取大小 → 彈出參數對話框設定線程數/路徑 → 送 'D' 多線程下載。
此架構在區域網路環境下表現穩定,可作為 FTP/HTTP 多線程下載器的 Socket 層參考實作。