LineBasedFrameDecoder
基于行的解码器,遇到 "\n"、"\r\n"会被作为行分隔符
也就是说如果是传递过来的消息是两行,每一行消息就会做一个消息,解决粘包拆包问题
FixedLengthFrameDecoder
基于固定长度的解码器,比如
一开始包分成四个
+---+----+------+----+
| A | BC | DEFG | HI |
+---+----+------+----+
如果基于三个字节长度,那么这四个包会被解码成以下三个
+-----+-----+-----+
| ABC | DEF | GHI |
+-----+-----+-----+
---------------------
DelimiterBasedFrameDecoder
+--------------+
* | ABC\nDEF\r\n |
* +--------------+
由上面的包
基于分隔符的振解码器,注意使用'\n'分割会产生2个振,使用'\r\n'会产生1个振, DelimiterBasedFrameDecoder原则使用产生最小振的分隔符,即'\n'
所以就会被解码成下面的包
+-----+-----+
* | ABC | DEF |
* +-----+-----+
下面介绍一个最重要的一个解码器
LengthFieldBasedFrameDecoder
这个解码器有四个重要参数
lengthFieldOffset 长度标识符的偏移量
lengthFieldLength 长度表示的长度
lengthAdjustment 添加到长度字段的补偿值
initialBytesToStrip 跳过的字节数
比如有下面两个包,length转化成十进制之后是0x000C代表的是14,0x000C占据了两个字节
此时lengthFieldLength =2,由于0x000C之前没有字节了所以lengthFieldOffset=0,lengthAdjustment之后说,这里是0
在解码之后没过过滤字节,所以initialBytesToStrip=0
+--------+----------------+ +--------+----------------+
* | Length | Actual Content |----->| Length | Actual Content |
* | 0x000C | "HELLO, WORLD" | | 0x000C | "HELLO, WORLD" |
* +--------+----------------+ +--------+----------------+ ---------1
下面一个解码过程,与上述的唯一区别就是initialBytesToStrip=2,因为解码是从长度之后开始的。Length标识符只是告诉解码器读完长度之后还有14个字节要读
+--------+----------------+ +----------------+
* | Length | Actual Content |----->| Actual Content |
* | 0x000C | "HELLO, WORLD" | | "HELLO, WORLD" |
* +--------+----------------+ +----------------+ ---------------2
但是有时候length标识的长度包含了length标识符本身长度,也就是14+2,所以length标识符告诉解码器读完length之后还有16个字节要读,这明显是错误的,必须通过lengthAdjustment来纠正,这里lengthAdjustment=-2,其余三个参数和1一样
+--------+----------------+ +--------+----------------+
* | Length | Actual Content |----->| Length | Actual Content |
* | 0x000E | "HELLO, WORLD" | | 0x000E | "HELLO, WORLD" | -----------3
* +--------+----------------+ +--------+----------------+
下面这个例子在length前面又多了2个字节的header,所以
lengthFieldOffset=2,其余和1一样
+----------+----------+----------------+ +----------+----------+----------------+
* | Header 1 | Length | Actual Content |----->| Header 1 | Length | Actual Content |
* | 0xCAFE | 0x00000C | "HELLO, WORLD" | | 0xCAFE | 0x00000C | "HELLO, WORLD" |
* +----------+----------+----------------+ +----------+----------+----------------+------------4
下面这个例子中length标识符表示的长度是14,也就是说在读完length之后还要读14个字节,但是实际上内容还要不算header的内容,所以要额外多读取2个字节,所以lengthAdjustment=2,而且没有偏移量,所以
lengthFieldOffset=0
其余和4一样
+----------+----------+----------------+ +----------+----------+----------------+
* | Length | Header 1 | Actual Content |----->| Length | Header 1 | Actual Content |
* | 0x00000C | 0xCAFE | "HELLO, WORLD" | | 0x00000C | 0xCAFE | "HELLO, WORLD" |
* +----------+----------+----------------+ +----------+----------+----------------+-----------5
下面这种情况
lengthFieldOffset=1
lengthFieldLength = 2
这里0x000C是14,因为length和实际内容中间夹杂了1个字节的HDR2所以
lengthAdjustment=1.同时读取的内容舍弃了HDR1和length,所以
initialBytesToStrip=3
+------+--------+------+----------------+ +------+----------------+
* | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
* | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" |----------6
* +------+--------+------+----------------+ +------+----------------+
再看一种情况
lengthFieldOffset = 1
* lengthFieldLength = 2
这里0x0010= 16
我们需要读取length后面的12个字节
还有HDR2占据1个字节,所以需要读13个字节,因此
lengthAdjustment=-3
另外我们跳过了HDR1和Length,所以
initialBytesToStrip=3
+------+--------+------+----------------+ +------+----------------+
* | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
* | 0xCA | 0x0010 | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" |
* +------+--------+------+----------------+ +------+----------------+