天天看點

Netty源碼(三):Netty的粘包問題ByteToMessageDecoder1. 産生粘包和半包的原因2. 問題一:Netty如何實作編碼解碼的3.問題二:LengthFieldBasedFrameDecoder編碼器的實作

1. 産生粘包和半包的原因

粘包産生的原因:兩個包小于緩存區的大小,傳送資料會将兩個包都放在緩沖區中一起發送,就會産生粘包的問題。

半包産生的原因:當某一個包的大于緩沖區的大小,會被發送多次,每次就收到的就是一個不完整的資料包。

常見的處理手段:

Netty源碼(三):Netty的粘包問題ByteToMessageDecoder1. 産生粘包和半包的原因2. 問題一:Netty如何實作編碼解碼的3.問題二:LengthFieldBasedFrameDecoder編碼器的實作

netty對不同粘包半包問題的支援類

Netty源碼(三):Netty的粘包問題ByteToMessageDecoder1. 産生粘包和半包的原因2. 問題一:Netty如何實作編碼解碼的3.問題二:LengthFieldBasedFrameDecoder編碼器的實作

2. 問題一:Netty如何實作編碼解碼的

檢視

ByteToMessageDecoder

,該類是解碼器的實作類,檢視其中的

channelRead

方法

1.調用了

cumulator.cumulate()

方法來實作資料包的拼接的操作

2.

callDecode()

方法解析資料包

Netty源碼(三):Netty的粘包問題ByteToMessageDecoder1. 産生粘包和半包的原因2. 問題一:Netty如何實作編碼解碼的3.問題二:LengthFieldBasedFrameDecoder編碼器的實作

2.1 cumulator.cumulate()方法拼接資料包

跟進源碼,發現他分為兩步:

1.如果是第一個資料包,就直接傳回該資料包

2.如果不是第一個資料包,就将最新的資料追加導員來已經接收的資料包内

Netty源碼(三):Netty的粘包問題ByteToMessageDecoder1. 産生粘包和半包的原因2. 問題一:Netty如何實作編碼解碼的3.問題二:LengthFieldBasedFrameDecoder編碼器的實作

2.2

callDecode()

方法解析資料包

核心實作方法,

decodeRemovalReentryProtection

就是

callDecode

中的核心步驟

Netty源碼(三):Netty的粘包問題ByteToMessageDecoder1. 産生粘包和半包的原因2. 問題一:Netty如何實作編碼解碼的3.問題二:LengthFieldBasedFrameDecoder編碼器的實作

跟進源碼

decodeRemovalReentryProtection

的源碼,其中核心方法是514行的

decode

方法,但是此方法是一個抽象方法,也就是說

ByteToMessageDecoder

隻是一個模闆類,具體的decode方法實作在子類中

Netty源碼(三):Netty的粘包問題ByteToMessageDecoder1. 産生粘包和半包的原因2. 問題一:Netty如何實作編碼解碼的3.問題二:LengthFieldBasedFrameDecoder編碼器的實作

于是我們檢視

ByteToMessageDecoder

的一個子類

FixedLengthFrameDecoder

FixedLengthFrameDecoder

是固定長度的編碼解碼方式,如果資料不足會補充空格等資料,它的decode方法如下:

1.如果我們接受到的資料小于資料幀限制的長度,那麼無法解析資料,直接傳回null

2.否則調用

readRetainedSlice

方法進行解析,

readRetainedSlice

就是将

ByteBuf

切出

frameLength

長度的資料出來

Netty源碼(三):Netty的粘包問題ByteToMessageDecoder1. 産生粘包和半包的原因2. 問題一:Netty如何實作編碼解碼的3.問題二:LengthFieldBasedFrameDecoder編碼器的實作

總結:Netty提供了一個

ByteToMessageDecoder

模闆類,資料包的拼接交給該類完成,但是資料包的解析

decode

是一個抽象方法,具體實作交給子類完成。

3.問題二:LengthFieldBasedFrameDecoder編碼器的實作

核心就是其中的四個參數:

1.

lengthFieldOffset

// length字段的偏移量

2.l

engthFieldLength

// legnth字段所占的長度

3.

lengthAdjustment

// 可能我們除了實際内容字段以外,還額外增加2個字段的其他資訊,lengthAdjustment=2,那麼需要讀取的資料就是length+2

4.

initialBytesToStrip

// 我們解析出來的資料是從第幾位開始的,如果我們不需要接收length字段,那麼initialBytesToStrip=2,解析出來就隻有内容部分

Netty源碼(三):Netty的粘包問題ByteToMessageDecoder1. 産生粘包和半包的原因2. 問題一:Netty如何實作編碼解碼的3.問題二:LengthFieldBasedFrameDecoder編碼器的實作