首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

TCP 粘包/拆包深度解析:send/recv 不保證消息邊界

     編輯:程式設計綜合問答

Socket 編程中最容易踩的坑:send 兩次,recv 卻可能收到合併數據、半包數據,甚至兩者混合。本文從 TCP 流本質徹底講透應對策略。

核心誤區

TCP 是位元組流協議,無消息邊界概念。 發送方調用兩次 send,接收方一次 recv 可能讀到兩個包的內容;反之,一個完整邏輯包可能被拆分為多次 recv 返回。

為什麼會這樣?

  • Nagle 算法:小包合併發送,減少網絡開銷。
  • 接收緩衝區:滑動窗口機制,數據到達時間不固定。
  • 網絡設備:路由器、防火牆可能重組數據幀。

標準解決方案:應用層協議定義邊界

方案一:固定長度頭部

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 一次發完,需循環發送剩餘字節。
  • 關閉 Nagle:setsockopt(TCP_NODELAY) 適用於低延遲小包場景(如遊戲、即時通訊)。
  • 心跳機制檢測死連接,防止半打開狀態阻塞 recv。

理解「流」本質,設計健壯協議,Socket 通信才不會「斷斷續續」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved