入门指南:使用 Netty 解码数据的简明步骤

废话不多说直接开始

业务是程序需要接收两个互联网设备的数据,数据格式不一样,设备A是String,设备B是需要将每个字节进行解析。

实现处理多个设备过程

思路:我们定义一个转接处理器 TypeHandle。

 

java

复制代码

public class WSServerInitializer extends ChannelInitializer<NioSocketChannel> { @Override protected void initChannel(NioSocketChannel nioSocketChannel) { nioSocketChannel.pipeline().addLast(new TypeHandle()); } }

在这里继承 ChannelInitializer,它是一个父类方法。重写 channelRead 进行处理数据。

通过 ctx.pipeline().addLast(new StringHandle()); 进行添加处理器,通过ctx.fireChannelRead(str);进行数据转发。这样我们就可以在符合目标的处理器中处理数据了。字符串数据直接通过转字符串就可以了,不过多介绍这一点了。

 

java

复制代码

public class TypeHandle extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { String str = ((ByteBuf) msg).toString(StandardCharsets.UTF_8); if (str.startsWith("*CS") && str.endsWith("#")) { ctx.pipeline().addLast(new StringHandle()); ctx.fireChannelRead(str); } else { ctx.pipeline().addLast(new ByteDecodeHandle()); ctx.fireChannelRead(msg); } } }

看一下 StringHandle 的类,继承 SimpleChannelInboundHandler 类,并泛型指定 String。

SimpleChannelInboundHandler 是 Netty 框架中用于处理特定类型消息(字符串类型)的处理器。它是 Netty 中的一个泛型类,用于处理入站数据

 

java

复制代码

public class StringHandle extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) { } }

处理字节数据

首先我们先认识一下 ByteToMessageDecoder 解码器,用于将字节解码为消息对象,在网路通信中,数据是以字节流形式进行传输的,而 ByteToMessageDecoder 作用是实现了这一个过程。

触发时机

在自定义的 ByteDecodeHandle 类中我们继承了 ByteToMessageDecoder,所以当设备数据发送之后,会自动进入 decode 进行解码数据。decode 方法就是我们的解码方法,在这里我们主要对 ByteBuf 进行处理,它就是我们的数据。

 

java

复制代码

public class ByteDecodeHandle extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { } }

crc 校验

需要将数据传入指定算法中,首先 COPY 一个 bytebuf,因为读数据时,bytebuf中的指针会位移。不包括最后的2个字节数据,这是根据实际业务规定的。最终通过 calculateCRC16 进行校验。因为是 COPY 的 bytebuf,最后要释放一下资源,通过 release

 

java

复制代码

ByteBuf byteBuf = in.copy(); // 校验 CRC // 创建一个字节数组,长度为 copiedByteBuf 的可读字节数减去2(不包括倒数第二个字节) byte[] byteArray = new byte[byteBuf.readableBytes() - 2]; // 从 copiedByteBuf 中读取数据到字节数组中,从0读到倒数第二个字节 byteBuf.readBytes(byteArray); // 释放 copiedByteBuf byteBuf.release(); int i = CRC16.calculateCRC16(byteArray);

判断数据是否完整

image.png

getShortLE 是 bytebuf 的方法,用于获取小端序2个字节数据,参数6表示字节偏移6,可以看上面文档。通过 readableBytes 方法获取可读长度,如果小于数据长度,表示当前数据不完整。

 

java

复制代码

// 解析数据长度 short dataLength = in.getShortLE(6); // 判断数据是否完整 if (in.readableBytes() < dataLength) { System.out.println("数据不完整!"); }

读取 IMEI 16位字节的呢

由于 IMEI 是16位的字节数,我目前业务的实现方式是,将字节数组每一位转成 char,最后拼接起来转换成数字。

 

java

复制代码

// IMEI,读入 16位 byte[] dst = new byte[16]; in.getBytes(26, dst); StringBuilder sb = new StringBuilder(); // 将字节数组转换为字符串 for (byte b : dst) { if (b == 0) break; sb.append((char) b); } // 将字符串解析为数字 Long IMEI = Long.parseLong(sb.toString());

最后说一下读字节的方式,去除 LE 表示大端序

 

java

复制代码

# 获取四个字节 int productSN = in.getIntLE(8); # 获取一个字节 byte deviceType = in.getByte(12); # 获取一个字节,结果是 char char hardwareVersion = (char) in.getByte(13); # 获取两个字节 short backgroundAngle = in.getShortLE(18);

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值