Netty的LengthFieldBasedFrameDecoder使用

henry_wu001發表於2019-01-15

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個位元組。
 

相關文章