ZLOpdProtHandler.java 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package com.hb.proj.gather.protocol;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import com.hb.proj.gather.utils.ByteUtils;
  5. import com.hb.proj.gather.utils.Crc16Utils;
  6. import io.netty.buffer.ByteBuf;
  7. import io.netty.buffer.ByteBufUtil;
  8. import io.netty.channel.ChannelHandlerContext;
  9. import io.netty.channel.ChannelInboundHandlerAdapter;
  10. /**
  11. * 按协议解析数据 zl-opd mudbus 参考 A11标准
  12. * @author cwen
  13. *
  14. */
  15. public class ZLOpdProtHandler extends ChannelInboundHandlerAdapter {
  16. private final static Logger logger = LoggerFactory.getLogger(ZLOpdProtHandler.class);
  17. //整个处理链路中只执行一次,顺序靠前的执行
  18. @Override
  19. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  20. logger.info("有设备连接上:{}",ctx.channel().remoteAddress());
  21. }
  22. /**
  23. * 协议标准:0103[数据区字节数 1字节][数据区 若干字节][CRC16校验 2字节]
  24. * 01:dtu上位地址 03:表示读取
  25. *
  26. * 心跳2字节,间隔约30s
  27. */
  28. @Override
  29. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  30. //msg:如果设置了decoder编码器,则msg为编码后的类型,可强制转换
  31. ByteBuf byteBuf=(ByteBuf)msg;
  32. if(!byteBuf.isReadable()) {
  33. logger.info("没有数据可接收");
  34. return;
  35. }
  36. String hexmsg=ByteBufUtil.hexDump(byteBuf);
  37. logger.debug("接收到数据:{}",hexmsg);
  38. //byte[] temp=ByteBufUtil.getBytes(byteBuf, 0, 2);
  39. //两字节都没有既不是心跳也不是采集数据,忽略
  40. int byteCount=byteBuf.readableBytes();
  41. if(byteCount<2) {
  42. return ;
  43. }
  44. //开头两字节且不以0103开头,就认为是心跳数据-作为设备号,该方法并不可靠,有可能把采集的残包数据当作心跳
  45. if(byteCount==2&&(!hexmsg.startsWith("0103"))) {
  46. if(!ChannelGroupMgr.contains(ctx.channel())) {
  47. ChannelGroupMgr.add(ctx.channel(),ByteUtils.toIntStr(ByteBufUtil.getBytes(byteBuf,0,byteCount)));
  48. return;
  49. }
  50. }
  51. else if(byteCount>2&&hexmsg.startsWith("0103")){
  52. int headBtyCount=3,crc16BtyCount=2; //头部字节数,校验位字节数
  53. int datalen=byteBuf.getByte(2)&0xff; //数据区字节数 byteBuf.get方法不改变readIndex,writeIndex,readXX方法会
  54. logger.info("数据字节长度:{}",datalen);
  55. if(byteCount<(datalen+headBtyCount+crc16BtyCount)) { // 读取的字节数量不够---拆包了,目前处理:舍弃
  56. return;
  57. }
  58. //读取头部+数据区
  59. byte[] headAndDatas=ByteBufUtil.getBytes(byteBuf,0,headBtyCount+datalen);
  60. //读取校验位
  61. byte[] crc16=ByteBufUtil.getBytes(byteBuf,headBtyCount+datalen,2);
  62. int calCrc16=Crc16Utils.getCRC(headAndDatas);
  63. logger.info("接收CRC:{}:{},计算CRC:{}",ByteUtils.toHexString(crc16),ByteUtils.byte2ToIntHL(crc16),calCrc16);
  64. if(ByteUtils.byte2ToIntHL(crc16)==calCrc16) { //crc校验通过
  65. GatherRespParser.parseShort(byteBuf,headBtyCount,datalen);
  66. }
  67. }
  68. /**
  69. * 继续流转到下个handler 直到最后默认的tail handler 由它来释放
  70. * 关键点:数据能流转到最后、数据类型为byteBuf 中途没有被改变
  71. *
  72. * 也可创建继承SimpleChanneInboundHandler的自定义handler,实现channelRead0方法。
  73. * SimpleChannelInboundHandler负责释放
  74. */
  75. ctx.fireChannelRead(msg);
  76. }
  77. }