天天看點

Netty如何解決TCP的粘包半包問題?(下)1 TCP為何會有粘包半包?2 解決方案

1 TCP為何會有粘包半包?

1.1 粘包

  • 發送方每次寫入資料 < 套接字緩沖區大小
  • 接收方讀取套接字緩沖區資料不夠及時

1.2 半包

  • 發送方寫入資料 > 套接字緩沖區大小
  • 發送的資料大于協定的MTU ( Maximum Transmission Unit,最大傳輸單元),必須拆包

而且

  • 一個發送可能被多次接收,多個發送可能被一次接收
  • 一個發送可能占用多個傳輸包,多個發送可能公用一個傳輸包

本質是因為 TCP 是流式協定,消息無邊界。

UDP就像快遞,雖然一次運輸多個,但每個包都有邊界,一個個簽收,是以無此類問題。

清楚了問題本質,就知道如何避免了,即确定消息邊界。

2 解決方案

2.1 改為短連接配接

一個請求一個短連接配接。建立連接配接到釋放連接配接之間的資訊即為傳輸資訊。

簡單,但效率低下,不推薦。

2.2 封裝成幀

2.2.1 固定長度

  • 解碼:FixedLengthFrameDecoder
  • Netty如何解決TCP的粘包半包問題?(下)1 TCP為何會有粘包半包?2 解決方案
  • 滿足固定長度即可。
  • Netty如何解決TCP的粘包半包問題?(下)1 TCP為何會有粘包半包?2 解決方案
  • 簡單,但空間浪費,不推薦。

2.2.2 分割符

  • 解碼:DelimiterBasedFrameDecoder,分隔符之間即為消息。
  • Netty如何解決TCP的粘包半包問題?(下)1 TCP為何會有粘包半包?2 解決方案
  • 空間不浪費,也比較簡單,但内容本身出現分隔符時需轉義,是以需掃描内容。

推薦度低。

2.2.3 固定長度字段存個内容的長度資訊

解碼:LengthFieldBasedFrameDecoder

編碼:LengthFieldPrepender

先解析固定長度的字段擷取長度,然後讀取後續内容。這就沒有之前的缺點了

精确定位使用者資料,内容也不用轉義。

但長度理論上有限制,需提前預知可能的最大長度,進而定義長度占用位元組數。

如果直接定義成最大長度,但實際上每次傳輸的又遠沒達到最大值,不就浪費空間啦,是以根據需要設定最大長度。

重點推薦使用。

其他方式比如 json 可看{}是否已經成對。但這種明顯要掃描全部内容才知道是否成對。