对Netty总有一种莫名地执着,虽然还是一知半解,当做一种慢慢积累的过程。
我们来看一下Netty通用的拆包器LengthFieldBasedFrameDecoder
相关的使用,这个拆包器十分强大,几乎所有和长度相关的二进制协议都可以通过它来进行拆包。(以下图来自Netty源码注释)
这类的数据包协议是比较常见的,前面的几个字节表示数据包的长度(不包括长度域),后面是具体的数据。进行拆包之后,数据包就是一个完整的带有长度域的数据包。
整个数据包占据14bytes,而长度域0x000C为12(该字段表示是消息体正文的长度),那么长度域字段占据2个字节。
LengthFieldBasedFrameDecoder decoder = new LengthFieldBasedFrameDecoder(
Integer.MAX_VALUE, 0, 2);
使用以上的参数即可实现此类协议的拆包。
参数说明:
lengthFieldOffset
为0。
如果我们的解码器不需要利用到长度域字段,拆完包后整个数据包就只有消息体正文。我们只需要指定initialBytesToStrip参数即可。
LengthFieldBasedFrameDecoder decoder = new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,
0, 2, 0, 2);
前三个参数和前面是一样的,而第四个参数后面再利用,这不多做讲解。我们只需要指定initialBytesToStrip
参数即可。这里长度域字段占据2个字节,那么initialBytesToStrip
的值就为2,表示我们进行拆包的时候需要跳过2个字节。
这类二进制协议更加常见,前面几个固定字节表示的是协议头,紧接着表示的是一个长度域(这里也是表示消息体正文的字节数),最后才是消息体的正文。
由于长度域字段之前有个Header1,所以我们进行拆包时需要利用到lengthFieldOffset
,这里lengthFieldOffset为3。
LengthFieldBasedFrameDecoder decoder = new LengthFieldBasedFrameDecoder(
Integer.MAX_VALUE, 3, 2);
如果长度域在前,协议头在长度域之后,如何拆包?
这时候我们就需要利用到参数lengthAdjustment
了。
我们来分析一下参数设置的步骤:
lengthFieldOffset
为0,lengthFieldLength
为2。lengthAdjustment
,这个参数是用来调整包体的大小的,这里长度域的数值加上lengthAdjustment
这个调整值之后,就表示带有header的包。这里的Header 1的长度为3,那么lengthAdjustment
的值就为3,所以header和消息体正文一种占据15(12+3)个字节。LengthFieldBasedFrameDecoder decoder = new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0,
2, 3, 0);
这类的二进制协议会出现两个协议头。我们需要实现拆包后,只留下HDR2和消息体正文。这类协议包在RPC中比较常见,一般HDR1可以表示magicNumber,表示应用只接受以该magicNumber开头的二进制数据。
我们来分析一下:
lengthFieldOffset
为1,lengthFieldLength
为2。lengthAdjustment
为1。initialBytesToStrip
的值就为3。LengthFieldBasedFrameDecoder decoder = new LengthFieldBasedFrameDecoder(
Integer.MAX_VALUE, 1, 2, 1, 3);
之前的长度域都是只表示了消息体正文的长度,那么要是长度域表示的是整个数据包的大小,应该如何处理。
这里注意一下Length的参数,0x0010为16,表示的是整个数据包的大小,和情况5的图区分一下。
其他参数都不需要多作解释,我们只需要注意参数lengthAdjustment
即可,由于这次长度域表示的是整个数据包的长度,所以拆包时肯定会包含HDR2和消息体正文,可是会数据包会多出来一部分,这部分就是HDR1和Length的长度和,多出来的数据是不属于当前包的,那么就利用lengthAdjustment
对其进行调整,此时lengthAdjustment
为-3。那么包含HDR2和消息体正文的包体一共占据13个(16-3)字节。
LengthFieldBasedFrameDecoder decoder = new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,
1,2, -3, 3);
至此, LengthFieldBasedFrameDecoder的用法已经全部讲解完。LengthFieldBasedFrameDecoder拆包器的功能是十分强大的,足以应付大多数的二进制协议。
至于Netty源码暂时不去分析,这个以后再说。
参考:
netty源码分析之LengthFieldBasedFrameDecoder