問題一:recv 返回 1400 字節,網頁源碼不全
原因:TCP 是流式協議,**單次 `recv` 不保證接收完整應用層數據**。1400 約為 MTU(1500)減去 IP/TCP 頭部後的單包載荷,大數據需多次接收。
正確接收循環
char buf[20000] = {0};
int total = 0, n;
while ((n = recv(so, buf + total, sizeof(buf) - total - 1, 0)) > 0) {
total += n;
// 可選:解析 HTTP 頭部 Content-Length 或 Chunked 判斷結束
// 簡易版:連接關閉時 recv 返回 0 退出
}
buf[total] = '\0';
printf("Received %d bytes:\n%s", total, buf);
進階:解析 HTTP 響應長度
- **Content-Length**:讀取頭部,按指定長度讀取 Body。
- **Transfer-Encoding: chunked**:按塊大小循環讀取,遇 0 塊結束。
- **Connection: close**:服務端關閉連接標誌結束(HTTP/1.0 預設)。
問題二:換成 `www.stateair.net` 返回 404,瀏覽器卻能打開
原因:
- Host 頭缺失或錯誤:虛擬主機環境下,服務器根據 `Host` 頭路由請求。原代碼 `Host:www.csdn.net` 硬編碼,換網站需同步修改。
- User-Agent 缺失:部分站點拒絕無 UA 的請求。
- 重定向/HTTPS:目標站可能強制 HTTPS(443 端口)或返回 301/302 重定向,原代碼不處理。
- Cookie/Referer 等頭部:某些 API 需要完整頭部模擬瀏覽器。
修正請求示例
char request[] =
"GET / HTTP/1.1\r\n"
"Host: www.stateair.net\r\n"
"User-Agent: Mozilla/5.0 (compatible; MyBot/1.0)\r\n"
"Accept: */*\r\n"
"Connection: close\r\n"
"\r\n";
send(so, request, strlen(request), 0);
建議工具
- `wireshark` / `tcpdump` 抓包對比瀏覽器與程序請求差異。
- `curl -v https://www.stateair.net` 查看完整交互細節。
總結
- `recv` **必須循環調用**,直到邏輯判斷數據接收完畢。
- HTTP 請求**頭部要完整**(Host、UA、Accept 等),並支持重定向、HTTPS、Chunked 等機制。
- 抓包分析是排查網絡協議問題的**核心手段**。