之前的文章有寫過Netty的拆包處理Netty在Android開發中的應用實戰系列(四)——— 粘包 | 拆包 處理
一、這篇文章重點講一下Netty中自定義協議的拆包需要怎麼處理,也就是Netty提供的LengthFieldBasedFrameDecoder
拆包器
二、一般情況下我們都會定一個數據包的格式,如下:
包頭(共10個字節) | 擴展數據 | ||||
---|---|---|---|---|---|
標識符(2個字節) | 版本號(2個字節) | 擴展數據長度(4個字節) | 擴展數據類型(1個字節) | 保留字段(1個字節) | 若干個字節 |
- 協議中包頭的長度是固定的10個字節,而擴張數據長度在包頭中聲明瞭;所以我們整個包的
數據長度 = 包頭(固定10字節)+ 包頭中的擴展數據長度
- 這種數據包結構也就是比較常見的
當數據發生粘包的時候,只需要先解析到包頭 然後在解析包頭中的擴展數據長度 然後進行讀取數據,這樣就可以取到一個完整的數據包了
三、以上面這個數據包爲例,在Netty中需要怎麼添加拆包器呢?
- 在
pipeline
中添加LengthFieldFrameDecoder
即可
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new LengthFieldFrameDecoder();
//....
- 這裏先說下他的常用構造參數含義
- maxFrameLength
單個數據包的最大長度
- lengthFieldOffset
描述整個數據包的長度字節在數據包中的起始偏移量
- lengthFieldLength
描述整個數據包的長度在數據包中佔幾個字節
- lengthAdjustment
讀取數據包長度的校正值
- initialBytesToStrip
跳過多少個字節讀取
- maxFrameLength
第一個參數(maxFrameLength):如果你使用的協議有規定了每個包的數據最大長度那麼直接填規定好的長度,我這裏沒有所以我直接填Integer.MAX_VALUE
第二個參數(lengthFieldOffset):根據我的協議他的取值就是4
,從第四個字節開始
第三個參數(lengthFieldLength):根據我的協議他的取值也是4
,佔了四個字節
第四個參數(lengthAdjustment):有個計算公式:lengthAdjustment = 包頭長度 - (lengthFieldOffset + lengthFieldLength)
,所以這裏計算出來等於2
那麼最終代碼就會是這樣
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new LengthFieldFrameDecoder(Integer.MAX_VALUE, 4, 4, 2, 0));