# Netty分包器

1. 正文

   本分背景基于netty通过串口与硬件设备通信，但解决方案和思路在类似的通信应用里面基本都是通用的；具体介绍基于数据长度拆包，这种相对来说是比较灵活的解决方案。

   具体方案如下：

   * 对数据包(16进制)进行包装：

     在前面加上设备地址和数据包长度，最后两位为CRC校验位。
   * 在服务端对数据包进行拆包

     使用Netty中，基于长度域拆包器 LengthFieldBasedFrameDecoder，按照实际的应用层数据包长度来拆分。

     需要做两个工作：

     设置长度信息（长度域）在数据包中的位置。 设置长度信息（长度域）自身的长度，也就是占用的字节数。

     ```java
     public class PackageSpliter extends LengthFieldBasedFrameDecoder{

       public PackageSpliter() {
           super(Integer.MAX_VALUE, 1,1);
       }

       @Override
       protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {

           return super.decode(ctx, in);
       }
     }
     ```

     我们可以看到，分割器PackageSpliter继承了LengthFieldBasedFrameDecoder 并在构造里传入了三个参数。
   * 长度的偏移量 ，这里是 Constants.LENGTH\_OFFSET，值为 2；
   * 长度的字节数，这里是 Constants.LENGTH\_BYTES\_COUNT，值为 2
   * 最大的应用包长度，这里是 Integer.MAX\_VALUE，表示不限制

     分割器 写好之后，只需要在pipeline的最前面加上这个分割器，就可以使用这个分割器（自定义的拆包器）。

     但是为什么拆包器在pipline的最前面？

     ![](https://2205958781-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LRPUalxSxnd5GsCDfBO%2F-LSAXSIcWm3eWg3Xrb8C%2F-LSAXSjVuVJUTPQjIfpq%2Fpackspilterleitu.png?generation=1543160586166604\&alt=media)

     由此可见，分割器 PackageSpliter 继承了ChannelInboundHandlerAdapter。 本质上，它是一个入站处理器。 Netty的入站处理的顺序，是从pipelin 流水线的前面到后面。 所以，在入站过程中，解码器 ProtobufDecoder 进行应用层 protobuf 的数据包的解码，而在此之前，必须完成应用包的正确分割。 所以， 分割器 PackageSpliter 必须处于入站流水线处理的第一站，放在最前面。
