项目须要使用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被调用的时候还会包含以前全部没有被解析的字节内容。