文章目录
前言
这篇文章算是上篇文章 Netty解码器源码分析 的扩展篇 ,这里单独开一篇讲解这个特殊的解码器LengthFieldBasedFrameDecoder。
首先,它有什么用呢?有什么应用场景吗?这边我举一个例子,dubbo底层使用了Netty做了服务间通信来完成远程调用,其中应用层协议使用了自定义dubbo协议
偏移量(Bit) | 字段 | 取值 |
---|---|---|
0 ~ 7 | 魔数高位 | 0xda00 |
8 ~ 15 | 魔数低位 | 0xbb |
16 | 数据包类型 | 0 - Response, 1 - Request |
17 | 调用方式 | 仅在第16位被设为1的情况下有效,0 - 单向调用,1 - 双向调用 |
18 | 事件标识 | 0 - 当前数据包是请求或响应包,1 - 当前数据包是心跳包 |
19 ~ 23 | 序列化器编号 | 2 - Hessian2Serialization 3 - JavaSerialization 4 - CompactedJavaSerialization 6 - FastJsonSerialization 7 - NativeJavaSerialization 8 - KryoSerialization 9 - FstSerialization |
24 ~ 31 | 状态 | 20 - OK 30 - CLIENT_TIMEOUT 31 - SERVER_TIMEOUT 40 - BAD_REQUEST 50 - BAD_RESPONSE … |
32 ~ 95 | 请求编号 | 共8字节,运行时生成 |
96 ~ 127 | 消息体长度 | 运行时计算 |
图片、表格信息均摘自dubbo官方文档
以上表格代表整个消息头,也就是说,整个消息头的偏移量是固定的,例如96~127的偏移量的这个位置就是代表着消息体的长度,而不固定的是消息体,dubbo协议中消息体代表dubbo远程调用的一些信息例如接口版本、被调用的方法名、方法参数等等,这些信息是不一定的,这部分长度需要运行时才能计算出来,并且放入消息头中。那么,在解码的时候,我们就可以先接收固定长度(偏移量127bit长度)的消息头,将消息中固定偏移量(96~127)的内容先取出来,就可以知道接下来需要再接收多少长度的消息体,这样就算一个完整的数据包了。以上流程即可解码一个动态长度的数据包。
那么接下来就开始介绍,基于长度域的动态解码器。
基于长度域的动态解码器
使用介绍
在开始源码分析之前,这里先介绍一下怎么使用。如果有下载Netty源码,就可以看到LengthFieldBasedFrameDecoder中的类头有一大串注释,这串注释其实就很好的介绍了这个类的使用。那么就以这个类头来分析这个类能做什么。
先介绍一下四个参数分别什么意思,可以大致先了解一下,往下看你就更能理解这些参数了
- 需要拿到的动态长度信息的起始点(偏移量),dubbo协议中即为96
- 长度信息的长度,dubbo协议中即为32
- 长度修正量
- 需要剥离的长度
- lengthFieldOffset :0
- lengthFieldLength :2
- lengthAdjustment :0
- initialBytesToStrip :0
* BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)
* +--------+----------------+ +--------+----------------+
* | Length | Actual Content |----->| Length | Actual Content |
* | 0x000C | "HELLO, WORLD" | | 0x000C | "HELLO, WORLD" |
* +--------+----------------+ +--------+----------------+
首先,从0开始,长度为2,"HELLO, WORLD"字符串为12字节,也就是说前面Length占2字节,解码器截取前两字节,16进制0x000C = 12,加上lengthAdjustment,最终表示数据长度有12字节,剥离长度为0,则最终为14字节的完整数据。
- lengthFieldOffset :0
- lengthFieldLength :2
- lengthAdjustment :0
- initialBytesToStrip :2
* BEFORE DECODE (14 bytes) AFTER DECODE (12 bytes)
* +--------+----------------+ +----------------+
* | Length | Actual Content |----->| Actual Content |
* | 0x000C | "HELLO, WORLD" | | "HELLO, WORLD" |
* +--------+----------------+ +----------------+
这里和上面不同的就是,剥离长度为2,则剥离前两字节的内容,很简单,Length字段被剥离了,剩下12字节的数据包。
- lengthFieldOffset :0
- lengthFieldLength :2
- lengthAdjustment :-2
- initialBytesToStrip :0
* BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)
* +--------+----------------+ +--------+----------------+
* | Length | Actual Content |----->| Length | Actual Content |
* | 0x000E | "HELLO, WORLD" | | 0x000E | "HELLO, WORLD" |
* +--------+----------------+ +--------+----------------+
这里和第一个例子不同的就是修正量为-2,Length字段不再是12,而是14,也就是说计算长度的方法变了,拿到Length字段的值14之后,还需要加上修正量-2,结果还是为12字节的数据。
- lengthFieldOffset :2
- lengthFieldLength :3
- lengthAdjustment :0
- initialBytesToStrip :0
* BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes)
* +----------+----------+----------------+ +----------+----------+----------------+
* | Header 1 | Length | Actual Content |----->| Header 1 | Length | Actual Content |
* | 0xCAFE | 0x00000C | "HELLO, WORLD" | | 0xCAFE | 0x00000C | "HELLO, WORLD" |
* +----------+----------+----------------+ +----------+----------+----------------+
这里修改了偏移量的位置和Length长度的字节数,很好理解。
- lengthFieldOffset :1
- lengthFieldLength :2
- lengthAdjustment :1
- initialBytesToStrip :3
* BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes)
* +------+--------+------+----------------+ +------+----------------+
* | HDR1 | Length | HDR2 | Actual Co