使用 `CAsyncSocket`/`CSocket` 接收 HTTP 響應,成功解析出 Body 字符串 `"testtest"`,但寫入文件後大小為 0KB。調試時變量值正確,實際落盤為空。
resp_len = recv(sock, (char*)&buffer, BUFFER_SIZE, 0);
npos = string(buffer).find("\r\n\r\n", 0); // 定位 Header 結束
if (resp_len > 0) {
if (npos >= resp_len - 1 && flag) { /* Header 未接完 */ }
else if (npos < resp_len - 1 && flag) { /* 首包含 Body 部分 */
ofstream of("test.txt");
of << string(buffer).substr(npos + 4, resp_len - npos - 4);
flag = 0;
} else { /* 後續包全是 Body */
of << string(buffer).substr(0, resp_len);
}
}
string total_response;
char buf[4096];
int len;
while ((len = recv(sock, buf, sizeof(buf), 0)) > 0) {
total_response.append(buf, len);
// 可選:根據 Content-Length 判斷是否接收完畢
}
size_t header_end = total_response.find("\r\n\r\n");
if (header_end == string::npos) return; // 不完整
string header = total_response.substr(0, header_end);
string body = total_response.substr(header_end + 4);
// 簡易提取 Content-Length
regex cl_regex("Content-Length:\\s*(\\d+)", regex::icase);
smatch match;
size_t expected_len = 0;
if (regex_search(header, match, cl_regex))
expected_len = stoul(match[1].str());
// 若 body 長度不足,繼續 recv 補齊
while (body.length() < expected_len) {
len = recv(sock, buf, sizeof(buf), 0);
if (len <= 0) break;
body.append(buf, len);
}
ofstream of("test.txt", ios::binary);
of.write(body.c_str(), body.length());
of.close();
| 錯誤做法 | 正確做法 |
|---|---|
| 邊收邊寫,多次打開文件流 | 全量接收後,單次二進制寫入 |
| 假設首包含完整 Body | 根據 Content-Length 或 Chunked 判斷完整性 |
| 忽略 TCP 流無邊界特性 | 應用層協議(HTTP)定義邊界 |
| 文本模式寫入二進制數據 | 使用 `ios::binary` 避免換行符轉換 |
「調試時字符串正確,文件卻 0KB」經典現象,本質是TCP 流式傳輸與應用層邏輯不匹配。掌握「緩衝全量接收 → 協議解析長度 → 按長度截取/補齊 → 一次性落盤」這套標準流程,能解決 99% 的 Socket 文件下載問題。