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

时间:2023-03-09 14:51:00
使用Netty绑定一个端口如何分辨出多种类型的DTU的注册包

一、  背景

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

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

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

问题在于这是两个不同厂家的DTU,他们的注册报文的内容和长度都不相同。此时我们就无法使用诸如DelimitedBasedFrameDecoder、FixedLengthFrameDecoder这样现成的工具类来解决粘包的问题,需要自己去解析收到的每个字节,然后分别是判断对应的报文是哪种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被调用的时候还会包含之前所有没有被解析的字节内容。