Netty的LengthFieldBasedFrameDecoder使用
refs:
https://netty.io/5.0/api/io/netty/handler/codec/LengthFieldBasedFrameDecoder.html
https://blog.csdn.net/u014801432/article/details/81909902
https://blog.csdn.net/maosijunzi/article/details/78591667
https://github.com/thinkingfioa/netty-learning/tree/master/netty-private-protocol
https://blog.csdn.net/thinking_fioa
https://blog.csdn.net/column/details/22861.html
LengthFieldBasedFrameDecoder是netty解決拆包粘包問題的一個重要的類,主要結構就是header+body結構。我們只需要傳入正確的引數就可以傳送和接收正確的資料,那嗎重點就在於這幾個引數的意義。下面我們就具體瞭解一下這幾個引數的意義。先來看一下LengthFieldBasedFrameDecoder主要的構造方法:
public LengthFieldBasedFrameDecoder(
int maxFrameLength,
int lengthFieldOffset, int lengthFieldLength,
int lengthAdjustment, int initialBytesToStrip)
1
2
3
4
那麼這幾個重要的引數如下:
maxFrameLength:最大幀長度。也就是可以接收的資料的最大長度。如果超過,此次資料會被丟棄。
lengthFieldOffset:長度域偏移。就是說資料開始的幾個位元組可能不是表示資料長度,需要後移幾個位元組才是長度域。
lengthFieldLength:長度域位元組數。用幾個位元組來表示資料長度。
lengthAdjustment:資料長度修正。因為長度域指定的長度可以使header+body的整個長度,也可以只是body的長度。如果表示header+body的整個長度,那麼我們需要修正資料長度。
initialBytesToStrip:跳過的位元組數。如果你需要接收header+body的所有資料,此值就是0,如果你只想接收body資料,那麼需要跳過header所佔用的位元組數。
下面我們根據幾個例子的使用來具體說明這幾個引數的使用。
需求1
長度域為2個位元組,我們要求傳送和接收的資料如下所示:
* 傳送的資料 (14 bytes) 接收到資料 (14 bytes)
* +--------+----------------+ +--------+----------------+
* | Length | Actual Content |----->| Length | Actual Content |
* | 12 | "HELLO, WORLD" | | 12 | "HELLO, WORLD" |
* +--------+----------------+ +--------+----------------+
1
2
3
4
5
留心的你肯定發現了,長度域只是實際內容的長度,不包括長度域的長度。下面是引數的值:
lengthFieldOffset=0:開始的2個位元組就是長度域,所以不需要長度域偏移。
lengthFieldLength=2:長度域2個位元組。
lengthAdjustment=0:資料長度修正為0,因為長度域只包含資料的長度,所以不需要修正。
initialBytesToStrip=0:傳送和接收的資料完全一致,所以不需要跳過任何位元組。
需求2
長度域為2個位元組,我們要求傳送和接收的資料如下所示:
* 傳送的資料 (14 bytes) 接收到資料 (12 bytes)
* +--------+----------------+ +----------------+
* | Length | Actual Content |----->| Actual Content |
* | 12 | "HELLO, WORLD" | | "HELLO, WORLD" |
* +--------+----------------+ +----------------+
1
2
3
4
5
引數值如下:
lengthFieldOffset=0:開始的2個位元組就是長度域,所以不需要長度域偏移。
lengthFieldLength=2:長度域2個位元組。
lengthAdjustment=0:資料長度修正為0,因為長度域只包含資料的長度,所以不需要修正。
initialBytesToStrip=2:我們發現接收的資料沒有長度域的資料,所以要跳過長度域的2個位元組。
需求3
長度域為2個位元組,我們要求傳送和接收的資料如下所示:
* BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)
* +--------+----------------+ +--------+----------------+
* | Length | Actual Content |----->| Length | Actual Content |
* | 14 | "HELLO, WORLD" | | 14 | "HELLO, WORLD" |
* +--------+----------------+ +--------+----------------+
1
2
3
4
5
留心的你肯定又發現了,長度域表示的長度是總長度 也就是header+body的總長度。引數如下:
lengthFieldOffset=0:開始的2個位元組就是長度域,所以不需要長度域偏移。
lengthFieldLength=2:長度域2個位元組。
lengthAdjustment=-2:因為長度域為總長度,所以我們需要修正資料長度,也就是減去2。
initialBytesToStrip=0:我們發現接收的資料沒有長度域的資料,所以要跳過長度域的2個位元組。
需求4
長度域為2個位元組,我們要求傳送和接收的資料如下所示:
* BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes)
* +----------+----------+----------------+ +----------+----------+----------------+
* | meta | Length | Actual Content |----->| meta | Length | Actual Content |
* | 0xCAFE | 12 | "HELLO, WORLD" | | 0xCAFE | 12 | "HELLO, WORLD" |
* +----------+----------+----------------+ +----------+----------+----------------+
1
2
3
4
5
我們發現,資料的結構有點變化,變成了 meta+header+body的結構。meta一般表示後設資料,魔數等。我們定義這裡meta有三個位元組。引數如下:
lengthFieldOffset=3:開始的3個位元組是meta,然後才是長度域,所以長度域偏移為3。
lengthFieldLength=2:長度域2個位元組。
lengthAdjustment=0:長度域指定的長度位資料長度,所以資料長度不需要修正。
initialBytesToStrip=0:傳送和接收資料相同,不需要跳過資料。
需求5
長度域為2個位元組,我們要求傳送和接收的資料如下所示:
* BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes)
* +----------+----------+----------------+ +----------+----------+----------------+
* | Length | meta | Actual Content |----->| Length | meta | Actual Content |
* | 12 | 0xCAFE | "HELLO, WORLD" | | 12 | 0xCAFE | "HELLO, WORLD" |
* +----------+----------+----------------+ +----------+----------+----------------+
1
2
3
4
5
我們發現,資料的結構有點變化,變成了 header+meta+body的結構。meta一般表示後設資料,魔數等。我們定義這裡meta有三個位元組。引數如下:
lengthFieldOffset=0:開始的2個位元組就是長度域,所以不需要長度域偏移。
lengthFieldLength=2:長度域2個位元組。
lengthAdjustment=3:我們需要把meta+body當做body處理,所以資料長度需要加3。
initialBytesToStrip=0:傳送和接收資料相同,不需要跳過資料。
需求6
長度域為2個位元組,我們要求傳送和接收的資料如下所示:
* BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes)
* +------+--------+------+----------------+ +------+----------------+
* | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
* | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" |
* +------+--------+------+----------------+ +------+----------------+
1
2
3
4
5
我們發現,資料的結構有點變化,變成了 hdr1+header+hdr2+body的結構。我們定義這裡hdr1和hdr2都只有1個位元組。引數如下:
lengthFieldOffset=1:開始的1個位元組是長度域,所以需要設定長度域偏移為1。
lengthFieldLength=2:長度域2個位元組。
lengthAdjustment=1:我們需要把hdr2+body當做body處理,所以資料長度需要加1。
initialBytesToStrip=3:接收資料不包括hdr1和長度域相同,所以需要跳過3個位元組。
相關文章
- Netty原始碼分析之LengthFieldBasedFrameDecoderNetty原始碼
- netty系列之:在netty中使用proxy protocolNettyProtocol
- Netty中使用的設計模式Netty設計模式
- Netty入門系列(3) --使用Netty進行編解碼的操作Netty
- netty系列之:在netty中使用protobuf協議Netty協議
- netty系列之:使用netty搭建websocket客戶端NettyWeb客戶端
- netty系列之:使用netty搭建websocket伺服器NettyWeb伺服器
- netty系列之:使用netty實現支援http2的伺服器NettyHTTP伺服器
- Java使用Netty實現簡單的RPCJavaNettyRPC
- netty系列之:在netty中使用native傳輸協議Netty協議
- Netty使用及事件傳遞Netty事件
- netty系列之:netty對marshalling的支援Netty
- 初識Netty原理(一)—— 基本使用Netty
- 使用Netty模擬發生OOMNettyOOM
- netty系列之:使用POJO替代bufNettyPOJO
- netty系列之:使用UDP協議NettyUDP協議
- 在Netty使用中TLSv1.3NettyTLS
- Netty 的概述Netty
- netty 使用字典提升短文字的壓縮效果Netty
- netty系列之:protobuf在UDP協議中的使用NettyUDP協議
- netty系列之:netty中的Channel詳解Netty
- netty系列之:netty中的ByteBuf詳解Netty
- Netty入門系列(1) --使用Netty搭建服務端和客戶端Netty服務端客戶端
- 精通併發與 Netty (一)如何使用Netty
- Netty入門系列(2) --使用Netty解決粘包和拆包問題Netty
- netty系列之:netty對SOCKS協議的支援Netty協議
- netty系列之:netty中的frame解碼器Netty
- netty系列之:netty初探Netty
- Netty series: handling CORS in nettyNettyCORS
- Netty的wss支援Netty
- 聊聊netty的maxDirectMemoryNetty
- Netty的常用操作Netty
- netty系列之:Bootstrap,ServerBootstrap和netty中的實現NettybootServer
- netty系列之:netty中的核心解碼器jsonNettyJSON
- netty系列之:EventExecutor,EventExecutorGroup和netty中的實現Netty
- netty系列之:channel,ServerChannel和netty中的實現NettyServer
- netty系列之:netty中的核心MessageToMessage編碼器Netty
- netty系列之:netty中的核心MessageToByte編碼器Netty