之前的文章有写过Netty的拆包处理Netty在Android开发中的应用实战系列(四)——— 粘包 | 拆包 处理

一、这篇文章重点讲一下Netty中自定义协议的拆包需要怎么处理,也就是Netty提供的LengthFieldBasedFrameDecoder拆包器

二、一般情况下我们都会定一个数据包的格式,如下:

包头(共10个字节)

扩展数据

标识符(2个字节)

版本号(2个字节)

扩展数据长度(4个字节)

扩展数据类型(1个字节)

保留字段(1个字节)

若干个字节

  • 协议中包头的长度是固定的10个字节,而扩张数据长度在包头中声明了;所以我们整个包的 数据长度 = 包头(固定10字节)+ 包头中的扩展数据长度
  • 这种数据包结构也就是比较常见的
当数据发生粘包的时候,只需要先解析到包头 然后在解析包头中的扩展数据长度 然后进行读取数据,这样就可以取到一个完整的数据包了

三、以上面这个数据包为例,在Netty中需要怎么添加拆包器呢?

  • pipeline中添加LengthFieldFrameDecoder即可
ChannelPipeline pipeline = socketChannel.pipeline();
 
 pipeline.addLast(new LengthFieldFrameDecoder();
 //....
  • 这里先说下他的常用构造参数含义
  • maxFrameLength 单个数据包的最大长度
  • lengthFieldOffset 描述整个数据包的长度字节在数据包中的起始偏移量
  • lengthFieldLength 描述整个数据包的长度在数据包中占几个字节
  • lengthAdjustment 读取数据包长度的校正值
  • initialBytesToStrip 跳过多少个字节读取

第一个参数(maxFrameLength):如果你使用的协议有规定了每个包的数据最大长度那么直接填规定好的长度,我这里没有所以我直接填Integer.MAX_VALUE 第二个参数(lengthFieldOffset):根据我的协议他的取值就是4,从第四个字节开始
第三个参数(lengthFieldLength):根据我的协议他的取值也是4,占了四个字节
第四个参数(lengthAdjustment):有个计算公式:lengthAdjustment = 包头长度 - (lengthFieldOffset + lengthFieldLength) ,所以这里计算出来等于2

那么最终代码就会是这样
ChannelPipeline pipeline = socketChannel.pipeline();
 
 pipeline.addLast(new LengthFieldFrameDecoder(Integer.MAX_VALUE, 4, 4, 2, 0));