Netty - 粘包和半包(上)

在網絡傳輸中,粘包和半包應該是最常出現的問題,做爲 Java 中最常使用的 NIO 網絡框架 Netty,它又是如何解決的呢?今天就讓咱們來看看。 git

定義

TCP 傳輸中,客戶端發送數據,實際是把數據寫入到了 TCP 的緩存中,粘包和半包也就會在此時產生。github

客戶端給服務端發送了兩條消息ABCDEF,服務端這邊的接收會有多少種狀況呢?有多是一次性收到了全部的消息ABCDEF,有多是收到了三條消息ABCDEF緩存

上面所說的一次性收到了全部的消息ABCDEF,相似於粘包。若是客戶端發送的包的大小比 TCP 的緩存容量小,而且 TCP 緩存能夠存放多個包,那麼客戶端和服務端的一次通訊就可能傳遞了多個包,這時候服務端從 TCP 緩存就可能一下讀取了多個包,這種現象就叫粘包網絡

上面說的後面那種收到了三條消息ABCDEF,相似於半包。若是客戶端發送的包的大小比 TCP 的緩存容量大,那麼這個數據包就會被分紅多個包,經過 Socket 屢次發送到服務端,服務端第一次從接受緩存裏面獲取的數據,實際是整個包的一部分,這時候就產生了半包(半包不是說只收到了全包的一半,是說收到了全包的一部分)。框架

產生緣由

其實從上面的定義,咱們就能夠大概知道產生的緣由了。性能

粘包的主要緣由:編碼

  1. 發送方每次寫入數據 < 套接字(Socket)緩衝區大小
  2. 接收方讀取套接字(Socket)緩衝區數據不夠及時

半包的主要緣由:code

  1. 發送方每次寫入數據 > 套接字(Socket)緩衝區大小
  2. 發送的數據大於協議的 MTU (Maximum Transmission Unit,最大傳輸單元),所以必須拆包

其實咱們能夠換個角度看待問題:cdn

  1. 收發的角度看,即是一個發送可能被屢次接收,多個發送可能被一次接收。
  2. 傳輸的角度看,即是一個發送可能佔用多個傳輸包,多個發送可能共用一個傳輸包。

根本緣由,實際上是get

TCP 是流式協議,消息無邊界。

(PS : UDP 雖然也能夠一次傳輸多個包或者屢次傳輸一個包,但每一個消息都是有邊界的,所以不會有粘包和半包問題。)

解決方法

就像上面說的,UDP 之因此不會產生粘包和半包問題,主要是由於消息有邊界,所以,咱們也能夠採起相似的思路。

改爲短鏈接

將 TCP 鏈接改爲短鏈接,一個請求一個短鏈接。這樣的話,創建鏈接到釋放鏈接之間的消息即爲傳輸的信息,消息也就產生了邊界。

這樣的方法就是十分簡單,不須要在咱們的應用中作過多修改。但缺點也就很明顯了,效率低下,TCP 鏈接和斷開都會涉及三次握手以及四次握手,每一個消息都會涉及這些過程,十分浪費性能。

所以,並不推介這種方式。

封裝成幀

封裝成幀(Framing),也就是本來發送消息的單位是緩衝大小,如今換成了幀,這樣咱們就能夠自定義邊界了。通常有4種方式:

固定長度

這種方式下,消息邊界也就是固定長度便可。

優勢就是實現很簡單,缺點就是空間有極大的浪費,若是傳遞的消息中大部分都比較短,這樣就會有不少空間是浪費的。

所以,這種方式通常也是不推介的。

分隔符

這種方式下,消息邊界也就是分隔符自己。

優勢是空間再也不浪費,實現也比較簡單。缺點是當內容自己出現分割符時須要轉義,因此不管是發送仍是接受,都須要進行整個內容的掃描。

所以,這種方式效率也不是很高,但能夠嘗試使用。

專門的 length 字段

這種方式,就有點相似 Http 請求中的 Content-Length,有一個專門的字段存儲消息的長度。做爲服務端,接受消息時,先解析固定長度的字段(length字段)獲取消息總長度,而後讀取後續內容。

優勢是精肯定位用戶數據,內容也不用轉義。缺點是長度理論上有限制,須要提早限制可能的最大長度從而定義長度佔用字節數。

所以,十分推介用這種方式。

其餘方式

其餘方式就各不相同了,好比 JSON 能夠當作是使用{}是否成對。這些優缺點就須要你們在各自的場景中進行衡量了。

Netty 中的實現

Netty 支持上文所講的封裝成幀(Framing)中的前三種方式,簡單介紹下:

方式 解碼 編碼
固定長度 FixedLengthFrameDecoder 簡單
分割符 DelimiterBasedFrameDecoder 簡單
專門的 length 字段 LengthFieldBasedFrameDecoder LengthFieldPrepender

總結

今天主要介紹了粘包和半包問題、解決思路和 Netty 中的支持,我會在下一篇文章裏重點講述 Netty 中的具體實現,敬請期待。

有興趣的話能夠訪問個人博客或者關注個人公衆號、頭條號,說不定會有意外的驚喜。

death00.github.io/

相關文章
相關標籤/搜索