Socket 編程中最容易踩的坑:send 兩次,recv 卻可能收到合併數據、半包數據,甚至兩者混合。本文從 TCP 流本質徹底講透應對策略。
TCP 是位元組流協議,無消息邊界概念。 發送方調用兩次 send,接收方一次 recv 可能讀到兩個包的內容;反之,一個完整邏輯包可能被拆分為多次 recv 返回。
struct Header { uint32_t length; }; // 網絡序
// 發送:先發 Header,再發 Body
// 接收:先收 4 字節解析 length,再循環收滿 length 字節
如 HTTP 的 \r\n\r\n、自定義 |,適合文本協議,需處理轉義。
Protobuf、MessagePack 等二進制序列化庫內建長度前綴,推薦生產環境使用。
int recv_all(SOCKET s, void* buf, int len) {
int total = 0;
while (total < len) {
int n = recv(s, (char*)buf + total, len - total, 0);
if (n <= 0) return n; // 錯誤或斷開
total += n;
}
return total;
}
send 一次發完,需循環發送剩餘字節。setsockopt(TCP_NODELAY) 適用於低延遲小包場景(如遊戲、即時通訊)。recv。理解「流」本質,設計健壯協議,Socket 通信才不會「斷斷續續」。