1 TCP為何會有粘包半包?
1.1 粘包
- 發送方每次寫入資料 < 套接字緩沖區大小
- 接收方讀取套接字緩沖區資料不夠及時
1.2 半包
- 發送方寫入資料 > 套接字緩沖區大小
- 發送的資料大于協定的MTU ( Maximum Transmission Unit,最大傳輸單元),必須拆包
而且
- 一個發送可能被多次接收,多個發送可能被一次接收
- 一個發送可能占用多個傳輸包,多個發送可能公用一個傳輸包
本質是因為 TCP 是流式協定,消息無邊界。
UDP就像快遞,雖然一次運輸多個,但每個包都有邊界,一個個簽收,是以無此類問題。
清楚了問題本質,就知道如何避免了,即确定消息邊界。
2 解決方案
2.1 改為短連接配接
一個請求一個短連接配接。建立連接配接到釋放連接配接之間的資訊即為傳輸資訊。
簡單,但效率低下,不推薦。
2.2 封裝成幀
2.2.1 固定長度
- 解碼:FixedLengthFrameDecoder
- 滿足固定長度即可。
- 簡單,但空間浪費,不推薦。
2.2.2 分割符
- 解碼:DelimiterBasedFrameDecoder,分隔符之間即為消息。
- 空間不浪費,也比較簡單,但内容本身出現分隔符時需轉義,是以需掃描内容。
推薦度低。
2.2.3 固定長度字段存個内容的長度資訊
解碼:LengthFieldBasedFrameDecoder
編碼:LengthFieldPrepender
先解析固定長度的字段擷取長度,然後讀取後續内容。這就沒有之前的缺點了
精确定位使用者資料,内容也不用轉義。
但長度理論上有限制,需提前預知可能的最大長度,進而定義長度占用位元組數。
如果直接定義成最大長度,但實際上每次傳輸的又遠沒達到最大值,不就浪費空間啦,是以根據需要設定最大長度。
重點推薦使用。
其他方式比如 json 可看{}是否已經成對。但這種明顯要掃描全部内容才知道是否成對。