1. 程式人生 > >Netty拆包粘包以及編解碼技術

Netty拆包粘包以及編解碼技術

TCP拆包粘包

TCP是個流協議,所謂流就是沒有界限的一串資料。TCP底層並不瞭解上層業務資料的具體定義,它會根據TCP緩衝區的實際情況進行包的劃分,所以在業務上認為一個完整的包可能會被TCP拆分成多個包進行傳送,也有可能把多個小的包封裝成一個大的資料包傳送,這就是所謂的TCP粘包和拆包問題。

這裡寫圖片描述
TCP粘包拆包發生的原因:
問題產生的原因有三個,分別如下:

  • 應用程式Write寫入的位元組大小大於套介面傳送緩衝區的大小。
  • 進行MSS大小的TCP分段。
  • 乙太網幀的payload大於MTU進行IP分片。

這裡寫圖片描述
粘包問題的解決策略:
由於底層的TCP無法理解上層的業務資料,所以底層是無法保證資料包不被拆分和重組的,這個問題只能通過上層的應用協議棧設計來解決:

① 訊息定長,例如每個報文的大小為固定長度200位元組,如果不夠空位補空格。 ② 在包尾增加回車換行符進行分割,例如FTP協議。
③ 將訊息分為訊息頭和訊息體,訊息頭中包含表示訊息總長度(或者訊息體總體長度) 的欄位,通常涉及思路為訊息頭的第一個欄位使用init32來表示訊息的總長度。
④ 更復雜的應用層協議。

LineBasedFrameDecoder和StringDecoder的原理分析:

LineBasedFrameDecoder的工作原理是它依次便利ByteBuf中的可讀位元組,判斷看是否有“\n”或者“\r\n”,如果有就以此位置為結束位置,從可讀索引到結束位置區間的位元組就組成了一行。他是以換行符為結束標誌的解碼器,支援攜帶結束符或者不攜帶結束符兩種解碼方式,同時支援配置當行的最大長度。如果連續讀取帶最大長度後任然沒有發現換行符,就會丟擲異常,同時忽略掉之前讀到的異常碼流。

StringDecoder的功能非常簡單,就是將接收到的物件轉換成字串,然後繼續呼叫後面的handler。LineBasedFrameDecoder+StringDecoder組合就是按行切換的文字解碼器,它被設計用來支援TCP的粘包和拆包。
DelimiterBasedFrameDecoder特殊符號解碼器,其已經過濾掉了分隔符。

FixedLengthFrameDecoder固定長度解碼器,它能夠按照指定的長度對訊息進行自動解碼。利用FixedLengthFrameDecoder解碼器無論一次接受到多少資料報,它都會按照建構函式中設定的固定長度進行解碼,如果是半包訊息,FixedLengthFrameDecoder會快取半包訊息並等待下個包到達後進行拼包,直到取到一個完整的包。

編解碼技術

當進行遠端跨程序服務呼叫時,需要把傳輸的java物件編碼為位元組陣列或者ByteBuffer物件,而當遠端服務讀取到ByteBuffer物件或者位元組陣列時,需要將其解碼為傳送時的java物件,這被稱為java編解碼技術。
在遠端服務呼叫時(RPC)時,很少直接使用java序列化進行訊息的編解碼和傳輸。
Java序列化的缺點:

① 無法跨語言:java序列化技術是java語言內部的私有協議其他語言不支援。
③ 序列化效能太低。

可以使用第三方的序列化工具實現,此處不做介紹。