使用Netty绑定一个端口如何分辨出多种类型的DTU的注册包

一、  背景

项目需要使用NettyDTU(无线数据传输模块)通信,需要接入多种类型的DTU,每种dtu连接上来之后都首先会发送一个注册报文。需要解析该注册报文来实现:

1. 分辨出是哪种类型的dtu

2. 从注册报文中识别出注册码,以便决定该dtu下面连接的是哪个装置。

问题在于这是两个不同厂家的DTU,他们的注册报文的内容和长度都不相同。此时我们就无法使用诸如DelimitedBasedFrameDecoderFixedLengthFrameDecoder这样现成的工具类来解决粘包的问题,需要自己去解析收到的每个字节,然后分别是判断对应的报文是哪种DTU的注册报文,把不同种类的注册包解析成内部消息。

public class DtuLoginMessage {

    public enum DtuType{

       dtJingfuyuan,

       dtTopIot

    }

   

    private DtuType dtuType;

    private String regCode;

   

    public DtuType getDtuType() {

       return dtuType;

    }

 

    public String getRegCode() {

       return regCode;

    }  

   

    public DtuLoginMessage(DtuType type, String regCode){

       this.dtuType = type;

       this.regCode = regCode;

    }

}

 

 二、解决方案

既然无法无法使用工具类来解决粘包、拆包的问题,那就需要自己去解析每个字节,那就要自定义一个ChannelHandler子类来讲随机收到的ByteBuf转换为DtuLoginMessage,我们一般写ChannelHandler都是直接继承自ChannelInboundHandlerAdapter,然后去override他的channelRead方法,如果直接用这个类也不是不行,但是那就意味着自己要定义一个缓冲区来接受每次channelRead传递过来的字节,每次有新的字节过来,就要先写入到缓冲区,然后再去检查一下当前缓冲区的这些数据是否已经是某个dtu的注册包了,如果是的话就可以往后走了。这里存在的主要问题是要自己去维护这个缓冲区,如果有什么工具类可以帮我们维护就更好了,记得曾经在哪里看过。

没错,ByteToMessageDecoder就是干这活的,可以让自己的Handler继承ByteToMessageDecoder,然后重写其中的decode方法,该方法的签名如下,实例代码如下:

protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {    

DtuLoginMessage loginMsg = DtuLoginHandlerContainer.getInstance().decode(in);      

        if (loginMsg != null)

            out.add(loginMsg);

}

 

每次decode被调用,都去检查一下是否是某个dtu的注册包,如果是,就添加到out中;如果不是,那就什么都不用管,这样下次decode被调用的时候还会包含之前所有没有被解析的字节内容。





原文地址:https://www.cnblogs.com/strinkbug/p/5256153.html