Netty 解決粘包拆包

While parsing a protocol message, the input ended unexpectedly in the middle of a field. This could mean either that the input has been truncated or that an embedded message misreported its own length.java

出現上述這個問題我以爲是您使用protlcol的方式不對;也就是出現了粘包拆包的問題; 上一篇文章介紹了Netty中使用Protobuf的編碼解碼,下面介紹一下粘包拆包的問題;git

什麼是粘包、拆包?github

在基於流的傳輸裏好比TCP/IP,接收到的數據會先被存儲到一個socket接收緩衝裏。不幸的是,基於流的傳輸並非一個數據包隊列,而是一個字節隊列。即便你發送了2個獨立的數據包,操做系統也不會做爲2個消息處理而僅僅是做爲一連串的字節而言。 所以這是不能保證你遠程寫入的數據就會準確地讀取。舉個例子,讓咱們假設操做系統的TCP/TP協議棧已經接收了3個數據包:編程

在這裏插入圖片描述

因爲基於流傳輸的協議的這種普通的性質,在你的應用程序裏讀取數據的時候會有很高的可能性被分紅下面的片斷多線程

image.png

所以,一個接收方無論他是客戶端仍是服務端,都應該把接收到的數據整理成一個或者多個更有意思而且可以讓程序的業務邏輯更好理解的數據。在上面的例子中,接收到的數據應該被構形成下面的格式:併發

在這裏插入圖片描述

解決方法由以下幾種:框架

一、消息定長,報文大小固定長度,例如每一個報文的長度固定爲200字節,若是不夠空位補空格;socket

二、包尾添加特殊分隔符,例如每條報文結束都添加回車換行符(例如FTP協議)或者指定特殊字符做爲報文分隔符,接收方經過特殊分隔符切分報文區分;函數

三、將消息分爲消息頭和消息體,消息頭中包含表示信息的總長度(或者消息體長度)的字段;工具

Netty提供了多個解碼器,能夠進行分包的操做,分別是:

LineBasedFrameDecoder (利用換行符解決)

DelimiterBasedFrameDecoder(添加特殊分隔符報文來分包)

FixedLengthFrameDecoder(使用定長的報文來分包)

LengthFieldBasedFrameDecoder   
複製代碼

這裏咱們介紹一下LineBasedFrameDecoder(利用換行符解決)的使用方式:

LineBasedFrameDecoder 解碼器使用很是簡單,只須要在 pipline 鏈條上添加便可。

//字符串解析,換行防拆包
.addLast(new LineBasedFrameDecoder(1024))
.addLast(new StringDecoder())
複製代碼

構造函數中傳入了 1024 是指報的長度最大不超過這個值;

注意,因爲 LineBasedFrameDecoder 解碼器是經過換行符來判斷的,因此在發送時,一條完整的消息須要加上 \n。

例如:

在這裏插入圖片描述
Protocol 拆、粘包

接下來咱們使用Protocol 來解決,拆、粘包,用Protocol來解決拆、粘包那是至關簡單的. 只須要在服務端和客戶端加上這兩個編解碼工具便可:

//拆包解碼
.addLast(new ProtobufVarint32FrameDecoder())
.addLast(new ProtobufVarint32LengthFieldPrepender())
複製代碼

可是注意一點,添加pipeline鏈的時候必定要注意順序(我在寫案例的時候遇到的);具體請參考本案例代碼;

這個編解碼工具能夠簡單理解爲是在消息體中加了一個 32 位長度的整形字段,用於代表當前消息長度。

demo 地址:

當前項目:Netty框架--netty編碼解碼(項目中proto包下)

多線程併發編程(項目中thread包下)

BIO編程(項目中bio包下)

NIO編程(項目中nio包下)

自定義RPC(項目中rpc包下)

歡迎給個小星星鼓勵一下(記得Star哦,害羞臉).... 我只是給代碼注入靈魂

相關文章
相關標籤/搜索