diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java new file mode 100644 index 0000000..3620272 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java @@ -0,0 +1,23 @@ +package com.casic.missiles.parser.matcher.store; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; + +import java.util.concurrent.TimeUnit; + +public class MatchDataStore { + + private static ExpiringMap map = ExpiringMap.builder() + + .maxSize(100) + + .expiration(1, TimeUnit.SECONDS) + + .expirationPolicy(ExpirationPolicy.ACCESSED) + + .variableExpiration() + + .build(); + + +} diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java new file mode 100644 index 0000000..3620272 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java @@ -0,0 +1,23 @@ +package com.casic.missiles.parser.matcher.store; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; + +import java.util.concurrent.TimeUnit; + +public class MatchDataStore { + + private static ExpiringMap map = ExpiringMap.builder() + + .maxSize(100) + + .expiration(1, TimeUnit.SECONDS) + + .expirationPolicy(ExpirationPolicy.ACCESSED) + + .variableExpiration() + + .build(); + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java deleted file mode 100644 index deca495..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import io.netty.buffer.ByteBuf; - -/** - * @author cz - * @date 2023-7-5 - */ -public interface AbstractPreProcessing { - - ByteBuf decode(ByteBuf byteBuf); - -} diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java new file mode 100644 index 0000000..3620272 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java @@ -0,0 +1,23 @@ +package com.casic.missiles.parser.matcher.store; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; + +import java.util.concurrent.TimeUnit; + +public class MatchDataStore { + + private static ExpiringMap map = ExpiringMap.builder() + + .maxSize(100) + + .expiration(1, TimeUnit.SECONDS) + + .expirationPolicy(ExpirationPolicy.ACCESSED) + + .variableExpiration() + + .build(); + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java deleted file mode 100644 index deca495..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import io.netty.buffer.ByteBuf; - -/** - * @author cz - * @date 2023-7-5 - */ -public interface AbstractPreProcessing { - - ByteBuf decode(ByteBuf byteBuf); - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java new file mode 100644 index 0000000..172832c --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java @@ -0,0 +1,13 @@ +package com.casic.missiles.parser.predecodec; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + * @date 2023-7-5 + */ +public interface AbstractPretreatment { + + ByteBuf decode(ByteBuf byteBuf); + +} diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java new file mode 100644 index 0000000..3620272 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java @@ -0,0 +1,23 @@ +package com.casic.missiles.parser.matcher.store; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; + +import java.util.concurrent.TimeUnit; + +public class MatchDataStore { + + private static ExpiringMap map = ExpiringMap.builder() + + .maxSize(100) + + .expiration(1, TimeUnit.SECONDS) + + .expirationPolicy(ExpirationPolicy.ACCESSED) + + .variableExpiration() + + .build(); + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java deleted file mode 100644 index deca495..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import io.netty.buffer.ByteBuf; - -/** - * @author cz - * @date 2023-7-5 - */ -public interface AbstractPreProcessing { - - ByteBuf decode(ByteBuf byteBuf); - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java new file mode 100644 index 0000000..172832c --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java @@ -0,0 +1,13 @@ +package com.casic.missiles.parser.predecodec; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + * @date 2023-7-5 + */ +public interface AbstractPretreatment { + + ByteBuf decode(ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java deleted file mode 100644 index e8b72f5..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; - -import java.util.Stack; - -/** - * @author cz - */ -public class PreProcessingSupport { - /** - * 获取第一个大括号,对应的右括号下标值 - * 算法流程 - * 1、初始化totalRightBracket为0 - * 2、获取首个“{”压栈,totalRightBracket加偏移下标 - * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 - * (1)”{“,压栈,totalRightBracket加偏移下标 - * (2)“}”,出栈,totalRightBracket加偏移下标 - * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 - */ - protected Integer getFirstBraceIndex(String detectedContent) { - String tempContent = detectedContent; - Stack stack = new Stack(); - Integer first = detectedContent.indexOf("{"); - Integer totalRightBracket = 0; - totalRightBracket += ++first; - tempContent = tempContent.substring(first); - if (ObjectUtils.isNotEmpty(first)) { - stack.push(first); - while (!stack.isEmpty()) { - if (tempContent.indexOf("{") != -1 && - tempContent.indexOf("}") != -1 - && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { - Integer leftBracket = tempContent.indexOf("{"); - totalRightBracket += ++leftBracket; - tempContent = tempContent.substring(leftBracket); - stack.push(leftBracket); - } else if (tempContent.indexOf("}") != -1) { - Integer rightBracket = tempContent.indexOf("}"); - totalRightBracket += ++rightBracket; - tempContent = tempContent.substring(rightBracket); - stack.pop(); - } else { - return 0; - } - } - return totalRightBracket; - } - return 0; - } - -} diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java new file mode 100644 index 0000000..3620272 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java @@ -0,0 +1,23 @@ +package com.casic.missiles.parser.matcher.store; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; + +import java.util.concurrent.TimeUnit; + +public class MatchDataStore { + + private static ExpiringMap map = ExpiringMap.builder() + + .maxSize(100) + + .expiration(1, TimeUnit.SECONDS) + + .expirationPolicy(ExpirationPolicy.ACCESSED) + + .variableExpiration() + + .build(); + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java deleted file mode 100644 index deca495..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import io.netty.buffer.ByteBuf; - -/** - * @author cz - * @date 2023-7-5 - */ -public interface AbstractPreProcessing { - - ByteBuf decode(ByteBuf byteBuf); - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java new file mode 100644 index 0000000..172832c --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java @@ -0,0 +1,13 @@ +package com.casic.missiles.parser.predecodec; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + * @date 2023-7-5 + */ +public interface AbstractPretreatment { + + ByteBuf decode(ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java deleted file mode 100644 index e8b72f5..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; - -import java.util.Stack; - -/** - * @author cz - */ -public class PreProcessingSupport { - /** - * 获取第一个大括号,对应的右括号下标值 - * 算法流程 - * 1、初始化totalRightBracket为0 - * 2、获取首个“{”压栈,totalRightBracket加偏移下标 - * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 - * (1)”{“,压栈,totalRightBracket加偏移下标 - * (2)“}”,出栈,totalRightBracket加偏移下标 - * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 - */ - protected Integer getFirstBraceIndex(String detectedContent) { - String tempContent = detectedContent; - Stack stack = new Stack(); - Integer first = detectedContent.indexOf("{"); - Integer totalRightBracket = 0; - totalRightBracket += ++first; - tempContent = tempContent.substring(first); - if (ObjectUtils.isNotEmpty(first)) { - stack.push(first); - while (!stack.isEmpty()) { - if (tempContent.indexOf("{") != -1 && - tempContent.indexOf("}") != -1 - && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { - Integer leftBracket = tempContent.indexOf("{"); - totalRightBracket += ++leftBracket; - tempContent = tempContent.substring(leftBracket); - stack.push(leftBracket); - } else if (tempContent.indexOf("}") != -1) { - Integer rightBracket = tempContent.indexOf("}"); - totalRightBracket += ++rightBracket; - tempContent = tempContent.substring(rightBracket); - stack.pop(); - } else { - return 0; - } - } - return totalRightBracket; - } - return 0; - } - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java new file mode 100644 index 0000000..82b2886 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java @@ -0,0 +1,52 @@ +package com.casic.missiles.parser.predecodec; + +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; + +import java.util.Stack; + +/** + * @author cz + */ +public class PretreatmentSupport { + /** + * 获取第一个大括号,对应的右括号下标值 + * 算法流程 + * 1、初始化totalRightBracket为0 + * 2、获取首个“{”压栈,totalRightBracket加偏移下标 + * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 + * (1)”{“,压栈,totalRightBracket加偏移下标 + * (2)“}”,出栈,totalRightBracket加偏移下标 + * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 + */ + protected Integer getFirstBraceIndex(String detectedContent) { + String tempContent = detectedContent; + Stack stack = new Stack(); + Integer first = detectedContent.indexOf("{"); + Integer totalRightBracket = 0; + totalRightBracket += ++first; + tempContent = tempContent.substring(first); + if (ObjectUtils.isNotEmpty(first)) { + stack.push(first); + while (!stack.isEmpty()) { + if (tempContent.indexOf("{") != -1 && + tempContent.indexOf("}") != -1 + && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { + Integer leftBracket = tempContent.indexOf("{"); + totalRightBracket += ++leftBracket; + tempContent = tempContent.substring(leftBracket); + stack.push(leftBracket); + } else if (tempContent.indexOf("}") != -1) { + Integer rightBracket = tempContent.indexOf("}"); + totalRightBracket += ++rightBracket; + tempContent = tempContent.substring(rightBracket); + stack.pop(); + } else { + return 0; + } + } + return totalRightBracket; + } + return 0; + } + +} diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java new file mode 100644 index 0000000..3620272 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java @@ -0,0 +1,23 @@ +package com.casic.missiles.parser.matcher.store; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; + +import java.util.concurrent.TimeUnit; + +public class MatchDataStore { + + private static ExpiringMap map = ExpiringMap.builder() + + .maxSize(100) + + .expiration(1, TimeUnit.SECONDS) + + .expirationPolicy(ExpirationPolicy.ACCESSED) + + .variableExpiration() + + .build(); + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java deleted file mode 100644 index deca495..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import io.netty.buffer.ByteBuf; - -/** - * @author cz - * @date 2023-7-5 - */ -public interface AbstractPreProcessing { - - ByteBuf decode(ByteBuf byteBuf); - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java new file mode 100644 index 0000000..172832c --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java @@ -0,0 +1,13 @@ +package com.casic.missiles.parser.predecodec; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + * @date 2023-7-5 + */ +public interface AbstractPretreatment { + + ByteBuf decode(ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java deleted file mode 100644 index e8b72f5..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; - -import java.util.Stack; - -/** - * @author cz - */ -public class PreProcessingSupport { - /** - * 获取第一个大括号,对应的右括号下标值 - * 算法流程 - * 1、初始化totalRightBracket为0 - * 2、获取首个“{”压栈,totalRightBracket加偏移下标 - * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 - * (1)”{“,压栈,totalRightBracket加偏移下标 - * (2)“}”,出栈,totalRightBracket加偏移下标 - * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 - */ - protected Integer getFirstBraceIndex(String detectedContent) { - String tempContent = detectedContent; - Stack stack = new Stack(); - Integer first = detectedContent.indexOf("{"); - Integer totalRightBracket = 0; - totalRightBracket += ++first; - tempContent = tempContent.substring(first); - if (ObjectUtils.isNotEmpty(first)) { - stack.push(first); - while (!stack.isEmpty()) { - if (tempContent.indexOf("{") != -1 && - tempContent.indexOf("}") != -1 - && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { - Integer leftBracket = tempContent.indexOf("{"); - totalRightBracket += ++leftBracket; - tempContent = tempContent.substring(leftBracket); - stack.push(leftBracket); - } else if (tempContent.indexOf("}") != -1) { - Integer rightBracket = tempContent.indexOf("}"); - totalRightBracket += ++rightBracket; - tempContent = tempContent.substring(rightBracket); - stack.pop(); - } else { - return 0; - } - } - return totalRightBracket; - } - return 0; - } - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java new file mode 100644 index 0000000..82b2886 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java @@ -0,0 +1,52 @@ +package com.casic.missiles.parser.predecodec; + +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; + +import java.util.Stack; + +/** + * @author cz + */ +public class PretreatmentSupport { + /** + * 获取第一个大括号,对应的右括号下标值 + * 算法流程 + * 1、初始化totalRightBracket为0 + * 2、获取首个“{”压栈,totalRightBracket加偏移下标 + * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 + * (1)”{“,压栈,totalRightBracket加偏移下标 + * (2)“}”,出栈,totalRightBracket加偏移下标 + * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 + */ + protected Integer getFirstBraceIndex(String detectedContent) { + String tempContent = detectedContent; + Stack stack = new Stack(); + Integer first = detectedContent.indexOf("{"); + Integer totalRightBracket = 0; + totalRightBracket += ++first; + tempContent = tempContent.substring(first); + if (ObjectUtils.isNotEmpty(first)) { + stack.push(first); + while (!stack.isEmpty()) { + if (tempContent.indexOf("{") != -1 && + tempContent.indexOf("}") != -1 + && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { + Integer leftBracket = tempContent.indexOf("{"); + totalRightBracket += ++leftBracket; + tempContent = tempContent.substring(leftBracket); + stack.push(leftBracket); + } else if (tempContent.indexOf("}") != -1) { + Integer rightBracket = tempContent.indexOf("}"); + totalRightBracket += ++rightBracket; + tempContent = tempContent.substring(rightBracket); + stack.pop(); + } else { + return 0; + } + } + return totalRightBracket; + } + return 0; + } + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java deleted file mode 100644 index 20dfa01..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.casic.missiles.parser.predecodec.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; -import com.casic.missiles.parser.predecodec.PreProcessingSupport; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.base64.Base64Dialect; -import io.netty.util.internal.ObjectUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.core.annotation.Order; - -import java.nio.charset.Charset; -import java.util.Stack; - -/** - * @description: 将从接口取到的数据编码 - * @author: cz - * @create: 2023-05-04 15:15 - **/ -@Slf4j -@Order(0) -public class AepPreProcessing extends PreProcessingSupport implements AbstractPreProcessing { - - private final Base64Dialect dialect; - - public AepPreProcessing() { - this(Base64Dialect.STANDARD); - } - - public AepPreProcessing(Base64Dialect dialect) { - this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); - } - - //执行nb平台前的协议解析 预处理 - @Override - public ByteBuf decode(ByteBuf msg) { - ByteBuf plaintextBuf = msg; - //aep平台处理 - if (msg.toString(Charset.defaultCharset()).contains("aep")) { - String httpContent = msg.toString(Charset.defaultCharset()); - log.info(" String : " + msg.toString(Charset.defaultCharset())); - try { - //左括号排序,右括号排序,入栈出栈,直接解决问题 - String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); - String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); - String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); - msg.readBytes(firstBraceContent.length()); - msg.markReaderIndex(); - ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); - bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); - plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); - log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); - } catch (Exception ex) { - log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); - } - } - return plaintextBuf; - } - - - - -} diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java new file mode 100644 index 0000000..3620272 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java @@ -0,0 +1,23 @@ +package com.casic.missiles.parser.matcher.store; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; + +import java.util.concurrent.TimeUnit; + +public class MatchDataStore { + + private static ExpiringMap map = ExpiringMap.builder() + + .maxSize(100) + + .expiration(1, TimeUnit.SECONDS) + + .expirationPolicy(ExpirationPolicy.ACCESSED) + + .variableExpiration() + + .build(); + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java deleted file mode 100644 index deca495..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import io.netty.buffer.ByteBuf; - -/** - * @author cz - * @date 2023-7-5 - */ -public interface AbstractPreProcessing { - - ByteBuf decode(ByteBuf byteBuf); - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java new file mode 100644 index 0000000..172832c --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java @@ -0,0 +1,13 @@ +package com.casic.missiles.parser.predecodec; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + * @date 2023-7-5 + */ +public interface AbstractPretreatment { + + ByteBuf decode(ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java deleted file mode 100644 index e8b72f5..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; - -import java.util.Stack; - -/** - * @author cz - */ -public class PreProcessingSupport { - /** - * 获取第一个大括号,对应的右括号下标值 - * 算法流程 - * 1、初始化totalRightBracket为0 - * 2、获取首个“{”压栈,totalRightBracket加偏移下标 - * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 - * (1)”{“,压栈,totalRightBracket加偏移下标 - * (2)“}”,出栈,totalRightBracket加偏移下标 - * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 - */ - protected Integer getFirstBraceIndex(String detectedContent) { - String tempContent = detectedContent; - Stack stack = new Stack(); - Integer first = detectedContent.indexOf("{"); - Integer totalRightBracket = 0; - totalRightBracket += ++first; - tempContent = tempContent.substring(first); - if (ObjectUtils.isNotEmpty(first)) { - stack.push(first); - while (!stack.isEmpty()) { - if (tempContent.indexOf("{") != -1 && - tempContent.indexOf("}") != -1 - && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { - Integer leftBracket = tempContent.indexOf("{"); - totalRightBracket += ++leftBracket; - tempContent = tempContent.substring(leftBracket); - stack.push(leftBracket); - } else if (tempContent.indexOf("}") != -1) { - Integer rightBracket = tempContent.indexOf("}"); - totalRightBracket += ++rightBracket; - tempContent = tempContent.substring(rightBracket); - stack.pop(); - } else { - return 0; - } - } - return totalRightBracket; - } - return 0; - } - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java new file mode 100644 index 0000000..82b2886 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java @@ -0,0 +1,52 @@ +package com.casic.missiles.parser.predecodec; + +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; + +import java.util.Stack; + +/** + * @author cz + */ +public class PretreatmentSupport { + /** + * 获取第一个大括号,对应的右括号下标值 + * 算法流程 + * 1、初始化totalRightBracket为0 + * 2、获取首个“{”压栈,totalRightBracket加偏移下标 + * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 + * (1)”{“,压栈,totalRightBracket加偏移下标 + * (2)“}”,出栈,totalRightBracket加偏移下标 + * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 + */ + protected Integer getFirstBraceIndex(String detectedContent) { + String tempContent = detectedContent; + Stack stack = new Stack(); + Integer first = detectedContent.indexOf("{"); + Integer totalRightBracket = 0; + totalRightBracket += ++first; + tempContent = tempContent.substring(first); + if (ObjectUtils.isNotEmpty(first)) { + stack.push(first); + while (!stack.isEmpty()) { + if (tempContent.indexOf("{") != -1 && + tempContent.indexOf("}") != -1 + && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { + Integer leftBracket = tempContent.indexOf("{"); + totalRightBracket += ++leftBracket; + tempContent = tempContent.substring(leftBracket); + stack.push(leftBracket); + } else if (tempContent.indexOf("}") != -1) { + Integer rightBracket = tempContent.indexOf("}"); + totalRightBracket += ++rightBracket; + tempContent = tempContent.substring(rightBracket); + stack.pop(); + } else { + return 0; + } + } + return totalRightBracket; + } + return 0; + } + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java deleted file mode 100644 index 20dfa01..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.casic.missiles.parser.predecodec.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; -import com.casic.missiles.parser.predecodec.PreProcessingSupport; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.base64.Base64Dialect; -import io.netty.util.internal.ObjectUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.core.annotation.Order; - -import java.nio.charset.Charset; -import java.util.Stack; - -/** - * @description: 将从接口取到的数据编码 - * @author: cz - * @create: 2023-05-04 15:15 - **/ -@Slf4j -@Order(0) -public class AepPreProcessing extends PreProcessingSupport implements AbstractPreProcessing { - - private final Base64Dialect dialect; - - public AepPreProcessing() { - this(Base64Dialect.STANDARD); - } - - public AepPreProcessing(Base64Dialect dialect) { - this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); - } - - //执行nb平台前的协议解析 预处理 - @Override - public ByteBuf decode(ByteBuf msg) { - ByteBuf plaintextBuf = msg; - //aep平台处理 - if (msg.toString(Charset.defaultCharset()).contains("aep")) { - String httpContent = msg.toString(Charset.defaultCharset()); - log.info(" String : " + msg.toString(Charset.defaultCharset())); - try { - //左括号排序,右括号排序,入栈出栈,直接解决问题 - String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); - String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); - String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); - msg.readBytes(firstBraceContent.length()); - msg.markReaderIndex(); - ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); - bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); - plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); - log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); - } catch (Exception ex) { - log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); - } - } - return plaintextBuf; - } - - - - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java new file mode 100644 index 0000000..4898e46 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java @@ -0,0 +1,64 @@ +package com.casic.missiles.parser.predecodec.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; +import com.casic.missiles.parser.predecodec.PretreatmentSupport; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.base64.Base64; +import io.netty.handler.codec.base64.Base64Dialect; +import io.netty.util.internal.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; + +import java.nio.charset.Charset; + +/** + * @description: 将从接口取到的数据编码 + * @author: cz + * @create: 2023-05-04 15:15 + **/ +@Slf4j +@Order(0) +public class AepPretreatment extends PretreatmentSupport implements AbstractPretreatment { + + private final Base64Dialect dialect; + + public AepPretreatment() { + this(Base64Dialect.STANDARD); + } + + public AepPretreatment(Base64Dialect dialect) { + this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); + } + + //执行nb平台前的协议解析 预处理 + @Override + public ByteBuf decode(ByteBuf msg) { + ByteBuf plaintextBuf = msg; + //aep平台处理 + if (msg.toString(Charset.defaultCharset()).contains("aep")) { + String httpContent = msg.toString(Charset.defaultCharset()); + log.info(" String : " + msg.toString(Charset.defaultCharset())); + try { + //左括号排序,右括号排序,入栈出栈,直接解决问题 + String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); + String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); + String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); + msg.readBytes(firstBraceContent.length()); + msg.markReaderIndex(); + ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); + bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); + plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); + log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); + } catch (Exception ex) { + log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); + } + } + return plaintextBuf; + } + + +} diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java new file mode 100644 index 0000000..3620272 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java @@ -0,0 +1,23 @@ +package com.casic.missiles.parser.matcher.store; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; + +import java.util.concurrent.TimeUnit; + +public class MatchDataStore { + + private static ExpiringMap map = ExpiringMap.builder() + + .maxSize(100) + + .expiration(1, TimeUnit.SECONDS) + + .expirationPolicy(ExpirationPolicy.ACCESSED) + + .variableExpiration() + + .build(); + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java deleted file mode 100644 index deca495..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import io.netty.buffer.ByteBuf; - -/** - * @author cz - * @date 2023-7-5 - */ -public interface AbstractPreProcessing { - - ByteBuf decode(ByteBuf byteBuf); - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java new file mode 100644 index 0000000..172832c --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java @@ -0,0 +1,13 @@ +package com.casic.missiles.parser.predecodec; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + * @date 2023-7-5 + */ +public interface AbstractPretreatment { + + ByteBuf decode(ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java deleted file mode 100644 index e8b72f5..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; - -import java.util.Stack; - -/** - * @author cz - */ -public class PreProcessingSupport { - /** - * 获取第一个大括号,对应的右括号下标值 - * 算法流程 - * 1、初始化totalRightBracket为0 - * 2、获取首个“{”压栈,totalRightBracket加偏移下标 - * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 - * (1)”{“,压栈,totalRightBracket加偏移下标 - * (2)“}”,出栈,totalRightBracket加偏移下标 - * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 - */ - protected Integer getFirstBraceIndex(String detectedContent) { - String tempContent = detectedContent; - Stack stack = new Stack(); - Integer first = detectedContent.indexOf("{"); - Integer totalRightBracket = 0; - totalRightBracket += ++first; - tempContent = tempContent.substring(first); - if (ObjectUtils.isNotEmpty(first)) { - stack.push(first); - while (!stack.isEmpty()) { - if (tempContent.indexOf("{") != -1 && - tempContent.indexOf("}") != -1 - && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { - Integer leftBracket = tempContent.indexOf("{"); - totalRightBracket += ++leftBracket; - tempContent = tempContent.substring(leftBracket); - stack.push(leftBracket); - } else if (tempContent.indexOf("}") != -1) { - Integer rightBracket = tempContent.indexOf("}"); - totalRightBracket += ++rightBracket; - tempContent = tempContent.substring(rightBracket); - stack.pop(); - } else { - return 0; - } - } - return totalRightBracket; - } - return 0; - } - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java new file mode 100644 index 0000000..82b2886 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java @@ -0,0 +1,52 @@ +package com.casic.missiles.parser.predecodec; + +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; + +import java.util.Stack; + +/** + * @author cz + */ +public class PretreatmentSupport { + /** + * 获取第一个大括号,对应的右括号下标值 + * 算法流程 + * 1、初始化totalRightBracket为0 + * 2、获取首个“{”压栈,totalRightBracket加偏移下标 + * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 + * (1)”{“,压栈,totalRightBracket加偏移下标 + * (2)“}”,出栈,totalRightBracket加偏移下标 + * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 + */ + protected Integer getFirstBraceIndex(String detectedContent) { + String tempContent = detectedContent; + Stack stack = new Stack(); + Integer first = detectedContent.indexOf("{"); + Integer totalRightBracket = 0; + totalRightBracket += ++first; + tempContent = tempContent.substring(first); + if (ObjectUtils.isNotEmpty(first)) { + stack.push(first); + while (!stack.isEmpty()) { + if (tempContent.indexOf("{") != -1 && + tempContent.indexOf("}") != -1 + && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { + Integer leftBracket = tempContent.indexOf("{"); + totalRightBracket += ++leftBracket; + tempContent = tempContent.substring(leftBracket); + stack.push(leftBracket); + } else if (tempContent.indexOf("}") != -1) { + Integer rightBracket = tempContent.indexOf("}"); + totalRightBracket += ++rightBracket; + tempContent = tempContent.substring(rightBracket); + stack.pop(); + } else { + return 0; + } + } + return totalRightBracket; + } + return 0; + } + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java deleted file mode 100644 index 20dfa01..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.casic.missiles.parser.predecodec.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; -import com.casic.missiles.parser.predecodec.PreProcessingSupport; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.base64.Base64Dialect; -import io.netty.util.internal.ObjectUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.core.annotation.Order; - -import java.nio.charset.Charset; -import java.util.Stack; - -/** - * @description: 将从接口取到的数据编码 - * @author: cz - * @create: 2023-05-04 15:15 - **/ -@Slf4j -@Order(0) -public class AepPreProcessing extends PreProcessingSupport implements AbstractPreProcessing { - - private final Base64Dialect dialect; - - public AepPreProcessing() { - this(Base64Dialect.STANDARD); - } - - public AepPreProcessing(Base64Dialect dialect) { - this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); - } - - //执行nb平台前的协议解析 预处理 - @Override - public ByteBuf decode(ByteBuf msg) { - ByteBuf plaintextBuf = msg; - //aep平台处理 - if (msg.toString(Charset.defaultCharset()).contains("aep")) { - String httpContent = msg.toString(Charset.defaultCharset()); - log.info(" String : " + msg.toString(Charset.defaultCharset())); - try { - //左括号排序,右括号排序,入栈出栈,直接解决问题 - String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); - String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); - String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); - msg.readBytes(firstBraceContent.length()); - msg.markReaderIndex(); - ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); - bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); - plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); - log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); - } catch (Exception ex) { - log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); - } - } - return plaintextBuf; - } - - - - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java new file mode 100644 index 0000000..4898e46 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java @@ -0,0 +1,64 @@ +package com.casic.missiles.parser.predecodec.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; +import com.casic.missiles.parser.predecodec.PretreatmentSupport; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.base64.Base64; +import io.netty.handler.codec.base64.Base64Dialect; +import io.netty.util.internal.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; + +import java.nio.charset.Charset; + +/** + * @description: 将从接口取到的数据编码 + * @author: cz + * @create: 2023-05-04 15:15 + **/ +@Slf4j +@Order(0) +public class AepPretreatment extends PretreatmentSupport implements AbstractPretreatment { + + private final Base64Dialect dialect; + + public AepPretreatment() { + this(Base64Dialect.STANDARD); + } + + public AepPretreatment(Base64Dialect dialect) { + this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); + } + + //执行nb平台前的协议解析 预处理 + @Override + public ByteBuf decode(ByteBuf msg) { + ByteBuf plaintextBuf = msg; + //aep平台处理 + if (msg.toString(Charset.defaultCharset()).contains("aep")) { + String httpContent = msg.toString(Charset.defaultCharset()); + log.info(" String : " + msg.toString(Charset.defaultCharset())); + try { + //左括号排序,右括号排序,入栈出栈,直接解决问题 + String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); + String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); + String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); + msg.readBytes(firstBraceContent.length()); + msg.markReaderIndex(); + ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); + bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); + plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); + log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); + } catch (Exception ex) { + log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); + } + } + return plaintextBuf; + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java deleted file mode 100644 index f43f3aa..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.casic.missiles.parser.predecodec.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; -import com.casic.missiles.parser.predecodec.PreProcessingSupport; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.base64.Base64Dialect; -import io.netty.util.internal.ObjectUtil; -import lombok.extern.slf4j.Slf4j; - -import java.nio.charset.Charset; - -/** - * @author cz - */ -@Slf4j -public class NbPreProcessing extends PreProcessingSupport implements AbstractPreProcessing { - - private final Base64Dialect dialect; - - public NbPreProcessing() { - this(Base64Dialect.STANDARD); - } - - public NbPreProcessing(Base64Dialect dialect) { - this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); - } - - @Override - public ByteBuf decode(ByteBuf msg) { - ByteBuf plaintextBuf = msg; - //aep平台处理 - if (msg.toString(Charset.defaultCharset()).contains("aep")) { - String httpContent = msg.toString(Charset.defaultCharset()); - log.info(" String : " + msg.toString(Charset.defaultCharset())); - try { - //左括号排序,右括号排序,入栈出栈,直接解决问题 - String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); - String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); - String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); - msg.readBytes(firstBraceContent.length()); - msg.markReaderIndex(); - ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); - bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); - plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); - log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); - } catch (Exception ex) { - log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); - } - } - return plaintextBuf; - } - -} diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java new file mode 100644 index 0000000..3620272 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java @@ -0,0 +1,23 @@ +package com.casic.missiles.parser.matcher.store; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; + +import java.util.concurrent.TimeUnit; + +public class MatchDataStore { + + private static ExpiringMap map = ExpiringMap.builder() + + .maxSize(100) + + .expiration(1, TimeUnit.SECONDS) + + .expirationPolicy(ExpirationPolicy.ACCESSED) + + .variableExpiration() + + .build(); + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java deleted file mode 100644 index deca495..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import io.netty.buffer.ByteBuf; - -/** - * @author cz - * @date 2023-7-5 - */ -public interface AbstractPreProcessing { - - ByteBuf decode(ByteBuf byteBuf); - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java new file mode 100644 index 0000000..172832c --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java @@ -0,0 +1,13 @@ +package com.casic.missiles.parser.predecodec; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + * @date 2023-7-5 + */ +public interface AbstractPretreatment { + + ByteBuf decode(ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java deleted file mode 100644 index e8b72f5..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; - -import java.util.Stack; - -/** - * @author cz - */ -public class PreProcessingSupport { - /** - * 获取第一个大括号,对应的右括号下标值 - * 算法流程 - * 1、初始化totalRightBracket为0 - * 2、获取首个“{”压栈,totalRightBracket加偏移下标 - * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 - * (1)”{“,压栈,totalRightBracket加偏移下标 - * (2)“}”,出栈,totalRightBracket加偏移下标 - * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 - */ - protected Integer getFirstBraceIndex(String detectedContent) { - String tempContent = detectedContent; - Stack stack = new Stack(); - Integer first = detectedContent.indexOf("{"); - Integer totalRightBracket = 0; - totalRightBracket += ++first; - tempContent = tempContent.substring(first); - if (ObjectUtils.isNotEmpty(first)) { - stack.push(first); - while (!stack.isEmpty()) { - if (tempContent.indexOf("{") != -1 && - tempContent.indexOf("}") != -1 - && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { - Integer leftBracket = tempContent.indexOf("{"); - totalRightBracket += ++leftBracket; - tempContent = tempContent.substring(leftBracket); - stack.push(leftBracket); - } else if (tempContent.indexOf("}") != -1) { - Integer rightBracket = tempContent.indexOf("}"); - totalRightBracket += ++rightBracket; - tempContent = tempContent.substring(rightBracket); - stack.pop(); - } else { - return 0; - } - } - return totalRightBracket; - } - return 0; - } - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java new file mode 100644 index 0000000..82b2886 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java @@ -0,0 +1,52 @@ +package com.casic.missiles.parser.predecodec; + +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; + +import java.util.Stack; + +/** + * @author cz + */ +public class PretreatmentSupport { + /** + * 获取第一个大括号,对应的右括号下标值 + * 算法流程 + * 1、初始化totalRightBracket为0 + * 2、获取首个“{”压栈,totalRightBracket加偏移下标 + * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 + * (1)”{“,压栈,totalRightBracket加偏移下标 + * (2)“}”,出栈,totalRightBracket加偏移下标 + * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 + */ + protected Integer getFirstBraceIndex(String detectedContent) { + String tempContent = detectedContent; + Stack stack = new Stack(); + Integer first = detectedContent.indexOf("{"); + Integer totalRightBracket = 0; + totalRightBracket += ++first; + tempContent = tempContent.substring(first); + if (ObjectUtils.isNotEmpty(first)) { + stack.push(first); + while (!stack.isEmpty()) { + if (tempContent.indexOf("{") != -1 && + tempContent.indexOf("}") != -1 + && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { + Integer leftBracket = tempContent.indexOf("{"); + totalRightBracket += ++leftBracket; + tempContent = tempContent.substring(leftBracket); + stack.push(leftBracket); + } else if (tempContent.indexOf("}") != -1) { + Integer rightBracket = tempContent.indexOf("}"); + totalRightBracket += ++rightBracket; + tempContent = tempContent.substring(rightBracket); + stack.pop(); + } else { + return 0; + } + } + return totalRightBracket; + } + return 0; + } + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java deleted file mode 100644 index 20dfa01..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.casic.missiles.parser.predecodec.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; -import com.casic.missiles.parser.predecodec.PreProcessingSupport; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.base64.Base64Dialect; -import io.netty.util.internal.ObjectUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.core.annotation.Order; - -import java.nio.charset.Charset; -import java.util.Stack; - -/** - * @description: 将从接口取到的数据编码 - * @author: cz - * @create: 2023-05-04 15:15 - **/ -@Slf4j -@Order(0) -public class AepPreProcessing extends PreProcessingSupport implements AbstractPreProcessing { - - private final Base64Dialect dialect; - - public AepPreProcessing() { - this(Base64Dialect.STANDARD); - } - - public AepPreProcessing(Base64Dialect dialect) { - this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); - } - - //执行nb平台前的协议解析 预处理 - @Override - public ByteBuf decode(ByteBuf msg) { - ByteBuf plaintextBuf = msg; - //aep平台处理 - if (msg.toString(Charset.defaultCharset()).contains("aep")) { - String httpContent = msg.toString(Charset.defaultCharset()); - log.info(" String : " + msg.toString(Charset.defaultCharset())); - try { - //左括号排序,右括号排序,入栈出栈,直接解决问题 - String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); - String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); - String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); - msg.readBytes(firstBraceContent.length()); - msg.markReaderIndex(); - ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); - bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); - plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); - log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); - } catch (Exception ex) { - log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); - } - } - return plaintextBuf; - } - - - - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java new file mode 100644 index 0000000..4898e46 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java @@ -0,0 +1,64 @@ +package com.casic.missiles.parser.predecodec.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; +import com.casic.missiles.parser.predecodec.PretreatmentSupport; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.base64.Base64; +import io.netty.handler.codec.base64.Base64Dialect; +import io.netty.util.internal.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; + +import java.nio.charset.Charset; + +/** + * @description: 将从接口取到的数据编码 + * @author: cz + * @create: 2023-05-04 15:15 + **/ +@Slf4j +@Order(0) +public class AepPretreatment extends PretreatmentSupport implements AbstractPretreatment { + + private final Base64Dialect dialect; + + public AepPretreatment() { + this(Base64Dialect.STANDARD); + } + + public AepPretreatment(Base64Dialect dialect) { + this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); + } + + //执行nb平台前的协议解析 预处理 + @Override + public ByteBuf decode(ByteBuf msg) { + ByteBuf plaintextBuf = msg; + //aep平台处理 + if (msg.toString(Charset.defaultCharset()).contains("aep")) { + String httpContent = msg.toString(Charset.defaultCharset()); + log.info(" String : " + msg.toString(Charset.defaultCharset())); + try { + //左括号排序,右括号排序,入栈出栈,直接解决问题 + String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); + String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); + String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); + msg.readBytes(firstBraceContent.length()); + msg.markReaderIndex(); + ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); + bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); + plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); + log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); + } catch (Exception ex) { + log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); + } + } + return plaintextBuf; + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java deleted file mode 100644 index f43f3aa..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.casic.missiles.parser.predecodec.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; -import com.casic.missiles.parser.predecodec.PreProcessingSupport; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.base64.Base64Dialect; -import io.netty.util.internal.ObjectUtil; -import lombok.extern.slf4j.Slf4j; - -import java.nio.charset.Charset; - -/** - * @author cz - */ -@Slf4j -public class NbPreProcessing extends PreProcessingSupport implements AbstractPreProcessing { - - private final Base64Dialect dialect; - - public NbPreProcessing() { - this(Base64Dialect.STANDARD); - } - - public NbPreProcessing(Base64Dialect dialect) { - this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); - } - - @Override - public ByteBuf decode(ByteBuf msg) { - ByteBuf plaintextBuf = msg; - //aep平台处理 - if (msg.toString(Charset.defaultCharset()).contains("aep")) { - String httpContent = msg.toString(Charset.defaultCharset()); - log.info(" String : " + msg.toString(Charset.defaultCharset())); - try { - //左括号排序,右括号排序,入栈出栈,直接解决问题 - String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); - String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); - String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); - msg.readBytes(firstBraceContent.length()); - msg.markReaderIndex(); - ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); - bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); - plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); - log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); - } catch (Exception ex) { - log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); - } - } - return plaintextBuf; - } - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPretreatment.java new file mode 100644 index 0000000..03fb0e4 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPretreatment.java @@ -0,0 +1,58 @@ +package com.casic.missiles.parser.predecodec.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; +import com.casic.missiles.parser.predecodec.PretreatmentSupport; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.base64.Base64; +import io.netty.handler.codec.base64.Base64Dialect; +import io.netty.util.internal.ObjectUtil; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.Charset; + +/** + * @author cz + */ +@Slf4j +public class NbPretreatment extends PretreatmentSupport implements AbstractPretreatment { + + private final Base64Dialect dialect; + + public NbPretreatment() { + this(Base64Dialect.STANDARD); + } + + public NbPretreatment(Base64Dialect dialect) { + this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); + } + + @Override + public ByteBuf decode(ByteBuf msg) { + ByteBuf plaintextBuf = msg; + //aep平台处理 + if (msg.toString(Charset.defaultCharset()).contains("aep")) { + String httpContent = msg.toString(Charset.defaultCharset()); + log.info(" String : " + msg.toString(Charset.defaultCharset())); + try { + //左括号排序,右括号排序,入栈出栈,直接解决问题 + String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); + String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); + String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); + msg.readBytes(firstBraceContent.length()); + msg.markReaderIndex(); + ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); + bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); + plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); + log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); + } catch (Exception ex) { + log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); + } + } + return plaintextBuf; + } + +} diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java new file mode 100644 index 0000000..3620272 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java @@ -0,0 +1,23 @@ +package com.casic.missiles.parser.matcher.store; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; + +import java.util.concurrent.TimeUnit; + +public class MatchDataStore { + + private static ExpiringMap map = ExpiringMap.builder() + + .maxSize(100) + + .expiration(1, TimeUnit.SECONDS) + + .expirationPolicy(ExpirationPolicy.ACCESSED) + + .variableExpiration() + + .build(); + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java deleted file mode 100644 index deca495..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import io.netty.buffer.ByteBuf; - -/** - * @author cz - * @date 2023-7-5 - */ -public interface AbstractPreProcessing { - - ByteBuf decode(ByteBuf byteBuf); - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java new file mode 100644 index 0000000..172832c --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java @@ -0,0 +1,13 @@ +package com.casic.missiles.parser.predecodec; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + * @date 2023-7-5 + */ +public interface AbstractPretreatment { + + ByteBuf decode(ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java deleted file mode 100644 index e8b72f5..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; - -import java.util.Stack; - -/** - * @author cz - */ -public class PreProcessingSupport { - /** - * 获取第一个大括号,对应的右括号下标值 - * 算法流程 - * 1、初始化totalRightBracket为0 - * 2、获取首个“{”压栈,totalRightBracket加偏移下标 - * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 - * (1)”{“,压栈,totalRightBracket加偏移下标 - * (2)“}”,出栈,totalRightBracket加偏移下标 - * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 - */ - protected Integer getFirstBraceIndex(String detectedContent) { - String tempContent = detectedContent; - Stack stack = new Stack(); - Integer first = detectedContent.indexOf("{"); - Integer totalRightBracket = 0; - totalRightBracket += ++first; - tempContent = tempContent.substring(first); - if (ObjectUtils.isNotEmpty(first)) { - stack.push(first); - while (!stack.isEmpty()) { - if (tempContent.indexOf("{") != -1 && - tempContent.indexOf("}") != -1 - && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { - Integer leftBracket = tempContent.indexOf("{"); - totalRightBracket += ++leftBracket; - tempContent = tempContent.substring(leftBracket); - stack.push(leftBracket); - } else if (tempContent.indexOf("}") != -1) { - Integer rightBracket = tempContent.indexOf("}"); - totalRightBracket += ++rightBracket; - tempContent = tempContent.substring(rightBracket); - stack.pop(); - } else { - return 0; - } - } - return totalRightBracket; - } - return 0; - } - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java new file mode 100644 index 0000000..82b2886 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java @@ -0,0 +1,52 @@ +package com.casic.missiles.parser.predecodec; + +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; + +import java.util.Stack; + +/** + * @author cz + */ +public class PretreatmentSupport { + /** + * 获取第一个大括号,对应的右括号下标值 + * 算法流程 + * 1、初始化totalRightBracket为0 + * 2、获取首个“{”压栈,totalRightBracket加偏移下标 + * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 + * (1)”{“,压栈,totalRightBracket加偏移下标 + * (2)“}”,出栈,totalRightBracket加偏移下标 + * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 + */ + protected Integer getFirstBraceIndex(String detectedContent) { + String tempContent = detectedContent; + Stack stack = new Stack(); + Integer first = detectedContent.indexOf("{"); + Integer totalRightBracket = 0; + totalRightBracket += ++first; + tempContent = tempContent.substring(first); + if (ObjectUtils.isNotEmpty(first)) { + stack.push(first); + while (!stack.isEmpty()) { + if (tempContent.indexOf("{") != -1 && + tempContent.indexOf("}") != -1 + && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { + Integer leftBracket = tempContent.indexOf("{"); + totalRightBracket += ++leftBracket; + tempContent = tempContent.substring(leftBracket); + stack.push(leftBracket); + } else if (tempContent.indexOf("}") != -1) { + Integer rightBracket = tempContent.indexOf("}"); + totalRightBracket += ++rightBracket; + tempContent = tempContent.substring(rightBracket); + stack.pop(); + } else { + return 0; + } + } + return totalRightBracket; + } + return 0; + } + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java deleted file mode 100644 index 20dfa01..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.casic.missiles.parser.predecodec.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; -import com.casic.missiles.parser.predecodec.PreProcessingSupport; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.base64.Base64Dialect; -import io.netty.util.internal.ObjectUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.core.annotation.Order; - -import java.nio.charset.Charset; -import java.util.Stack; - -/** - * @description: 将从接口取到的数据编码 - * @author: cz - * @create: 2023-05-04 15:15 - **/ -@Slf4j -@Order(0) -public class AepPreProcessing extends PreProcessingSupport implements AbstractPreProcessing { - - private final Base64Dialect dialect; - - public AepPreProcessing() { - this(Base64Dialect.STANDARD); - } - - public AepPreProcessing(Base64Dialect dialect) { - this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); - } - - //执行nb平台前的协议解析 预处理 - @Override - public ByteBuf decode(ByteBuf msg) { - ByteBuf plaintextBuf = msg; - //aep平台处理 - if (msg.toString(Charset.defaultCharset()).contains("aep")) { - String httpContent = msg.toString(Charset.defaultCharset()); - log.info(" String : " + msg.toString(Charset.defaultCharset())); - try { - //左括号排序,右括号排序,入栈出栈,直接解决问题 - String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); - String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); - String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); - msg.readBytes(firstBraceContent.length()); - msg.markReaderIndex(); - ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); - bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); - plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); - log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); - } catch (Exception ex) { - log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); - } - } - return plaintextBuf; - } - - - - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java new file mode 100644 index 0000000..4898e46 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java @@ -0,0 +1,64 @@ +package com.casic.missiles.parser.predecodec.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; +import com.casic.missiles.parser.predecodec.PretreatmentSupport; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.base64.Base64; +import io.netty.handler.codec.base64.Base64Dialect; +import io.netty.util.internal.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; + +import java.nio.charset.Charset; + +/** + * @description: 将从接口取到的数据编码 + * @author: cz + * @create: 2023-05-04 15:15 + **/ +@Slf4j +@Order(0) +public class AepPretreatment extends PretreatmentSupport implements AbstractPretreatment { + + private final Base64Dialect dialect; + + public AepPretreatment() { + this(Base64Dialect.STANDARD); + } + + public AepPretreatment(Base64Dialect dialect) { + this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); + } + + //执行nb平台前的协议解析 预处理 + @Override + public ByteBuf decode(ByteBuf msg) { + ByteBuf plaintextBuf = msg; + //aep平台处理 + if (msg.toString(Charset.defaultCharset()).contains("aep")) { + String httpContent = msg.toString(Charset.defaultCharset()); + log.info(" String : " + msg.toString(Charset.defaultCharset())); + try { + //左括号排序,右括号排序,入栈出栈,直接解决问题 + String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); + String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); + String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); + msg.readBytes(firstBraceContent.length()); + msg.markReaderIndex(); + ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); + bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); + plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); + log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); + } catch (Exception ex) { + log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); + } + } + return plaintextBuf; + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java deleted file mode 100644 index f43f3aa..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.casic.missiles.parser.predecodec.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; -import com.casic.missiles.parser.predecodec.PreProcessingSupport; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.base64.Base64Dialect; -import io.netty.util.internal.ObjectUtil; -import lombok.extern.slf4j.Slf4j; - -import java.nio.charset.Charset; - -/** - * @author cz - */ -@Slf4j -public class NbPreProcessing extends PreProcessingSupport implements AbstractPreProcessing { - - private final Base64Dialect dialect; - - public NbPreProcessing() { - this(Base64Dialect.STANDARD); - } - - public NbPreProcessing(Base64Dialect dialect) { - this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); - } - - @Override - public ByteBuf decode(ByteBuf msg) { - ByteBuf plaintextBuf = msg; - //aep平台处理 - if (msg.toString(Charset.defaultCharset()).contains("aep")) { - String httpContent = msg.toString(Charset.defaultCharset()); - log.info(" String : " + msg.toString(Charset.defaultCharset())); - try { - //左括号排序,右括号排序,入栈出栈,直接解决问题 - String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); - String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); - String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); - msg.readBytes(firstBraceContent.length()); - msg.markReaderIndex(); - ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); - bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); - plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); - log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); - } catch (Exception ex) { - log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); - } - } - return plaintextBuf; - } - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPretreatment.java new file mode 100644 index 0000000..03fb0e4 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPretreatment.java @@ -0,0 +1,58 @@ +package com.casic.missiles.parser.predecodec.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; +import com.casic.missiles.parser.predecodec.PretreatmentSupport; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.base64.Base64; +import io.netty.handler.codec.base64.Base64Dialect; +import io.netty.util.internal.ObjectUtil; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.Charset; + +/** + * @author cz + */ +@Slf4j +public class NbPretreatment extends PretreatmentSupport implements AbstractPretreatment { + + private final Base64Dialect dialect; + + public NbPretreatment() { + this(Base64Dialect.STANDARD); + } + + public NbPretreatment(Base64Dialect dialect) { + this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); + } + + @Override + public ByteBuf decode(ByteBuf msg) { + ByteBuf plaintextBuf = msg; + //aep平台处理 + if (msg.toString(Charset.defaultCharset()).contains("aep")) { + String httpContent = msg.toString(Charset.defaultCharset()); + log.info(" String : " + msg.toString(Charset.defaultCharset())); + try { + //左括号排序,右括号排序,入栈出栈,直接解决问题 + String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); + String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); + String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); + msg.readBytes(firstBraceContent.length()); + msg.markReaderIndex(); + ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); + bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); + plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); + log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); + } catch (Exception ex) { + log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); + } + } + return plaintextBuf; + } + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index a52aceb..3d5cc26 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -14,10 +14,13 @@ public class SensorhubReplier extends SimpleChannelInboundHandler { /** - * 回复分为一下情况 - * 1、成功返回时间 - * 2、如果有下发配置,下发配置(组建配置) - * 3、版本升级,下位机下发版本,是否升级,是上版本,是升级,请求,回复升级等流程 + * 该类方法是回复内容构建的流程入口类 + * 1、通过有标准协议解析器传来的结果进行命令的构建 + * 2、构建命令有以下的命令内容 + * (1)成功返回时间,并进行下发配置操作 + * (2)版本升级 + * (3)下位机下发版本是否升级,是上版本,是升级,请求,回复升级等流程 + * (4)其他未知需求命令 */ @Override public void channelRead0(ChannelHandlerContext ctx, Object obj) throws Exception { diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java new file mode 100644 index 0000000..3620272 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java @@ -0,0 +1,23 @@ +package com.casic.missiles.parser.matcher.store; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; + +import java.util.concurrent.TimeUnit; + +public class MatchDataStore { + + private static ExpiringMap map = ExpiringMap.builder() + + .maxSize(100) + + .expiration(1, TimeUnit.SECONDS) + + .expirationPolicy(ExpirationPolicy.ACCESSED) + + .variableExpiration() + + .build(); + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java deleted file mode 100644 index deca495..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import io.netty.buffer.ByteBuf; - -/** - * @author cz - * @date 2023-7-5 - */ -public interface AbstractPreProcessing { - - ByteBuf decode(ByteBuf byteBuf); - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java new file mode 100644 index 0000000..172832c --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java @@ -0,0 +1,13 @@ +package com.casic.missiles.parser.predecodec; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + * @date 2023-7-5 + */ +public interface AbstractPretreatment { + + ByteBuf decode(ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java deleted file mode 100644 index e8b72f5..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; - -import java.util.Stack; - -/** - * @author cz - */ -public class PreProcessingSupport { - /** - * 获取第一个大括号,对应的右括号下标值 - * 算法流程 - * 1、初始化totalRightBracket为0 - * 2、获取首个“{”压栈,totalRightBracket加偏移下标 - * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 - * (1)”{“,压栈,totalRightBracket加偏移下标 - * (2)“}”,出栈,totalRightBracket加偏移下标 - * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 - */ - protected Integer getFirstBraceIndex(String detectedContent) { - String tempContent = detectedContent; - Stack stack = new Stack(); - Integer first = detectedContent.indexOf("{"); - Integer totalRightBracket = 0; - totalRightBracket += ++first; - tempContent = tempContent.substring(first); - if (ObjectUtils.isNotEmpty(first)) { - stack.push(first); - while (!stack.isEmpty()) { - if (tempContent.indexOf("{") != -1 && - tempContent.indexOf("}") != -1 - && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { - Integer leftBracket = tempContent.indexOf("{"); - totalRightBracket += ++leftBracket; - tempContent = tempContent.substring(leftBracket); - stack.push(leftBracket); - } else if (tempContent.indexOf("}") != -1) { - Integer rightBracket = tempContent.indexOf("}"); - totalRightBracket += ++rightBracket; - tempContent = tempContent.substring(rightBracket); - stack.pop(); - } else { - return 0; - } - } - return totalRightBracket; - } - return 0; - } - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java new file mode 100644 index 0000000..82b2886 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java @@ -0,0 +1,52 @@ +package com.casic.missiles.parser.predecodec; + +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; + +import java.util.Stack; + +/** + * @author cz + */ +public class PretreatmentSupport { + /** + * 获取第一个大括号,对应的右括号下标值 + * 算法流程 + * 1、初始化totalRightBracket为0 + * 2、获取首个“{”压栈,totalRightBracket加偏移下标 + * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 + * (1)”{“,压栈,totalRightBracket加偏移下标 + * (2)“}”,出栈,totalRightBracket加偏移下标 + * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 + */ + protected Integer getFirstBraceIndex(String detectedContent) { + String tempContent = detectedContent; + Stack stack = new Stack(); + Integer first = detectedContent.indexOf("{"); + Integer totalRightBracket = 0; + totalRightBracket += ++first; + tempContent = tempContent.substring(first); + if (ObjectUtils.isNotEmpty(first)) { + stack.push(first); + while (!stack.isEmpty()) { + if (tempContent.indexOf("{") != -1 && + tempContent.indexOf("}") != -1 + && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { + Integer leftBracket = tempContent.indexOf("{"); + totalRightBracket += ++leftBracket; + tempContent = tempContent.substring(leftBracket); + stack.push(leftBracket); + } else if (tempContent.indexOf("}") != -1) { + Integer rightBracket = tempContent.indexOf("}"); + totalRightBracket += ++rightBracket; + tempContent = tempContent.substring(rightBracket); + stack.pop(); + } else { + return 0; + } + } + return totalRightBracket; + } + return 0; + } + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java deleted file mode 100644 index 20dfa01..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.casic.missiles.parser.predecodec.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; -import com.casic.missiles.parser.predecodec.PreProcessingSupport; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.base64.Base64Dialect; -import io.netty.util.internal.ObjectUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.core.annotation.Order; - -import java.nio.charset.Charset; -import java.util.Stack; - -/** - * @description: 将从接口取到的数据编码 - * @author: cz - * @create: 2023-05-04 15:15 - **/ -@Slf4j -@Order(0) -public class AepPreProcessing extends PreProcessingSupport implements AbstractPreProcessing { - - private final Base64Dialect dialect; - - public AepPreProcessing() { - this(Base64Dialect.STANDARD); - } - - public AepPreProcessing(Base64Dialect dialect) { - this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); - } - - //执行nb平台前的协议解析 预处理 - @Override - public ByteBuf decode(ByteBuf msg) { - ByteBuf plaintextBuf = msg; - //aep平台处理 - if (msg.toString(Charset.defaultCharset()).contains("aep")) { - String httpContent = msg.toString(Charset.defaultCharset()); - log.info(" String : " + msg.toString(Charset.defaultCharset())); - try { - //左括号排序,右括号排序,入栈出栈,直接解决问题 - String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); - String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); - String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); - msg.readBytes(firstBraceContent.length()); - msg.markReaderIndex(); - ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); - bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); - plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); - log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); - } catch (Exception ex) { - log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); - } - } - return plaintextBuf; - } - - - - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java new file mode 100644 index 0000000..4898e46 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java @@ -0,0 +1,64 @@ +package com.casic.missiles.parser.predecodec.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; +import com.casic.missiles.parser.predecodec.PretreatmentSupport; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.base64.Base64; +import io.netty.handler.codec.base64.Base64Dialect; +import io.netty.util.internal.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; + +import java.nio.charset.Charset; + +/** + * @description: 将从接口取到的数据编码 + * @author: cz + * @create: 2023-05-04 15:15 + **/ +@Slf4j +@Order(0) +public class AepPretreatment extends PretreatmentSupport implements AbstractPretreatment { + + private final Base64Dialect dialect; + + public AepPretreatment() { + this(Base64Dialect.STANDARD); + } + + public AepPretreatment(Base64Dialect dialect) { + this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); + } + + //执行nb平台前的协议解析 预处理 + @Override + public ByteBuf decode(ByteBuf msg) { + ByteBuf plaintextBuf = msg; + //aep平台处理 + if (msg.toString(Charset.defaultCharset()).contains("aep")) { + String httpContent = msg.toString(Charset.defaultCharset()); + log.info(" String : " + msg.toString(Charset.defaultCharset())); + try { + //左括号排序,右括号排序,入栈出栈,直接解决问题 + String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); + String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); + String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); + msg.readBytes(firstBraceContent.length()); + msg.markReaderIndex(); + ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); + bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); + plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); + log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); + } catch (Exception ex) { + log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); + } + } + return plaintextBuf; + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java deleted file mode 100644 index f43f3aa..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.casic.missiles.parser.predecodec.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; -import com.casic.missiles.parser.predecodec.PreProcessingSupport; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.base64.Base64Dialect; -import io.netty.util.internal.ObjectUtil; -import lombok.extern.slf4j.Slf4j; - -import java.nio.charset.Charset; - -/** - * @author cz - */ -@Slf4j -public class NbPreProcessing extends PreProcessingSupport implements AbstractPreProcessing { - - private final Base64Dialect dialect; - - public NbPreProcessing() { - this(Base64Dialect.STANDARD); - } - - public NbPreProcessing(Base64Dialect dialect) { - this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); - } - - @Override - public ByteBuf decode(ByteBuf msg) { - ByteBuf plaintextBuf = msg; - //aep平台处理 - if (msg.toString(Charset.defaultCharset()).contains("aep")) { - String httpContent = msg.toString(Charset.defaultCharset()); - log.info(" String : " + msg.toString(Charset.defaultCharset())); - try { - //左括号排序,右括号排序,入栈出栈,直接解决问题 - String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); - String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); - String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); - msg.readBytes(firstBraceContent.length()); - msg.markReaderIndex(); - ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); - bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); - plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); - log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); - } catch (Exception ex) { - log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); - } - } - return plaintextBuf; - } - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPretreatment.java new file mode 100644 index 0000000..03fb0e4 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPretreatment.java @@ -0,0 +1,58 @@ +package com.casic.missiles.parser.predecodec.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; +import com.casic.missiles.parser.predecodec.PretreatmentSupport; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.base64.Base64; +import io.netty.handler.codec.base64.Base64Dialect; +import io.netty.util.internal.ObjectUtil; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.Charset; + +/** + * @author cz + */ +@Slf4j +public class NbPretreatment extends PretreatmentSupport implements AbstractPretreatment { + + private final Base64Dialect dialect; + + public NbPretreatment() { + this(Base64Dialect.STANDARD); + } + + public NbPretreatment(Base64Dialect dialect) { + this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); + } + + @Override + public ByteBuf decode(ByteBuf msg) { + ByteBuf plaintextBuf = msg; + //aep平台处理 + if (msg.toString(Charset.defaultCharset()).contains("aep")) { + String httpContent = msg.toString(Charset.defaultCharset()); + log.info(" String : " + msg.toString(Charset.defaultCharset())); + try { + //左括号排序,右括号排序,入栈出栈,直接解决问题 + String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); + String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); + String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); + msg.readBytes(firstBraceContent.length()); + msg.markReaderIndex(); + ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); + bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); + plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); + log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); + } catch (Exception ex) { + log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); + } + } + return plaintextBuf; + } + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index a52aceb..3d5cc26 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -14,10 +14,13 @@ public class SensorhubReplier extends SimpleChannelInboundHandler { /** - * 回复分为一下情况 - * 1、成功返回时间 - * 2、如果有下发配置,下发配置(组建配置) - * 3、版本升级,下位机下发版本,是否升级,是上版本,是升级,请求,回复升级等流程 + * 该类方法是回复内容构建的流程入口类 + * 1、通过有标准协议解析器传来的结果进行命令的构建 + * 2、构建命令有以下的命令内容 + * (1)成功返回时间,并进行下发配置操作 + * (2)版本升级 + * (3)下位机下发版本是否升级,是上版本,是升级,请求,回复升级等流程 + * (4)其他未知需求命令 */ @Override public void channelRead0(ChannelHandlerContext ctx, Object obj) throws Exception { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index f5b5613..5616e16 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -25,7 +25,8 @@ public class DataReplyCommand extends ReplyCommandSupport implements AbstractBuildReplyCommand { /** - * 构建流程如下: + * 成功解析帧结构内容,进行下发成功回复命令的主要流程方法 + *其构建流程逻辑如下: * 1、初始化反构配置 * 2、进行业务内容的构建 * (1)默认为时间的构建 diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 632d189..3ff3358 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,6 +36,12 @@ 0.0.1-SNAPSHOT + + net.jodah + expiringmap + 0.5.8 + + diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java index 5a44f3e..43bc4d4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/SensorhubServer.java @@ -56,9 +56,9 @@ * 启动sensorhub服务 */ public void startServer() { -// new Thread(new Runnable() { -// @Override -// public void run() { + new Thread(new Runnable() { + @Override + public void run() { Integer port = sensorhubProperties.getPort(); if (port == null) { log.info("sensorhub服务端口不能为空"); @@ -84,8 +84,8 @@ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } -// } -// }).start(); + } + }).start(); } @PreDestroy diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 7e8cb16..c3f82cc 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -14,6 +14,8 @@ */ public class SensorhubServerChannelInitialHandler extends ChannelInitializer { + + @Override protected void initChannel(SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index eb167d6..afa062a 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -20,13 +20,14 @@ import java.util.Map; /** - * @author + * @author cz + * 通用的协议解析器,这里存在流程的主要解析流程 */ @Slf4j public class GenericProtocolParser extends ProtocolParserSupport implements ProtocolParser, ReplyCommandEnum { /** - * TO DO: 该集合用于数据报文的的数据解析 + * todo: 标准数据报文的核心解析流程方法 * 1、前导码匹配报文协议 * 2、构建协议工厂(初始化获取与协议有关的数据库配置) * 3、检测帧结构是否完整 @@ -36,7 +37,7 @@ * 7、构建回复需要的返回内容,为回复做准备 * * @param byteBuf 报文内容 - * @return 构建回复需要的返回内容,为回复做准备 + * @return 构建回复需要的返回内容,为回复handler准备相关命令 */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { @@ -44,7 +45,7 @@ ProtocolConfig protocolConfig = LeadingCodeMatcher.matchFrameLeadingCode(byteBuf); //如果匹配不到前导码,则重置byteByf,判断是否是二次拆包发送,进行再次匹配 if (ObjectUtil.isEmpty(protocolConfig)) { - return rematch(byteBuf); + return null; } //暂时先取第一个, 减少类的创建销毁与构建 AbstractProtocolConfigFactory protocolFactory = new DefaultProtocolConfigFactory(protocolConfig); @@ -61,20 +62,20 @@ DatagramEventConfig datagramEventConfig = datagramEventProvider.getProcessorInstance(); //处理粘包拆包的主要组合 List frameStructDispenserList = ClazzUtil.getSubClassList(FrameStructMatcher.class, true); - ByteBuf wholeNewPlainBuf = null; + ByteBuf intactMessageByte = null; //通过匹配帧结构获取完整的数据包,验证是否是一个完整的帧结构 for (FrameStructMatcher frameStructMatcher : frameStructDispenserList) { //帧结构该协议,经过帧结构判断选定帧协议完整的数据报文 - if ((wholeNewPlainBuf = frameStructMatcher.getWholeDatagram(byteBuf, protocolFactory, datagramEventConfig)) != null) { + if ((intactMessageByte = frameStructMatcher.getIntactMessageByte(byteBuf, protocolFactory, datagramEventConfig)) != null) { break; } } //没有匹配成功 - if (ObjectUtil.isEmpty(wholeNewPlainBuf)) { + if (ObjectUtil.isEmpty(intactMessageByte)) { return ParseResult.builder().replyCommand(NONE_DATA).build(); } //获取报文的业务内容 - ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(wholeNewPlainBuf); + ByteBuf bizDataByteBuf = protocolFactory.getProtocolFieldConfigProvider().getDataContentBuf(intactMessageByte); //密文解析 ByteBuf clearZeroPlainBuf = datagramEventProvider.getSafeDatagram(bizDataByteBuf, ruleConfigFactory.getFieldConfigProvider().getFieldConfigsMap()); //解析组合业务字段 @@ -93,21 +94,4 @@ return result; } - - /** - * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 - */ - private ParseResult rematch(ByteBuf byteBuf) { - String oldDataContent = ByteBufUtil.hexDump(byteBuf); - //重置位判断 - byteBuf.resetReaderIndex(); - //判断重置是否前移,如果没有前移,则直接判为匹配失败 - if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { - return ParseResult.builder().replyCommand(NONE_DATA).build(); - } else { - //递归执行 - return doParseProtocol(byteBuf); - } - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java index d13b643..b05b7ad 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/SensorhubDecoder.java @@ -3,19 +3,17 @@ import com.casic.missiles.enums.FrameAttributeEnums; import com.casic.missiles.enums.FrameStructEnum; import com.casic.missiles.enums.OperatorTypeEnum; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; import com.casic.missiles.pojo.Msg; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.util.ClazzUtil; import com.casic.missiles.util.MsgUtil; -import com.casic.missiles.util.SpringContextUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import sun.plugin2.gluegen.runtime.BufferFactory; import java.io.UnsupportedEncodingException; import java.util.List; @@ -26,31 +24,32 @@ @Slf4j public class SensorhubDecoder extends ByteToMessageDecoder { - // 帧的最小长度 - private static final int MIN_FRAME_LEN = 22; - /** - * 帧解析分为以下阶段 - * 1、帧前导码匹配 - * 2、帧规则解析 + * todo: 自定义协议解析 + * 帧解码分为以下阶段 + * 1、帧预处理,判断是否是标准的报文结构,可以通过各个平台的特点,进行拦截预处理,同时根据特点进行处理粘包问题,获取标准的报文 + * 2、将标准的报文,调用通用协议处理解析器,进行协议解析处理 + * 3、将从通用的协议解析器得到的结果进行保存到list,传递给回复的handler,进行相关的回复命令操作 */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { //添加前置处理器 - List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); - ByteBuf pretreatmentBuf = buffer; - for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { - pretreatmentBuf = abstractPreprocessing.decode(pretreatmentBuf); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPretreatment.class, true); + ByteBuf standardByteBuf = buffer; + for (AbstractPretreatment abstractPretreatment : abstractPreProcessingList) { + standardByteBuf = abstractPretreatment.decode(standardByteBuf); } - log.info(ByteBufUtil.hexDump(pretreatmentBuf)); + log.info(ByteBufUtil.hexDump(standardByteBuf)); //这里可以增加一些前置处理,例如判断拆包合包等网络流的操作 ProtocolParser protocolParser = new GenericProtocolParser(); - ParseResult parseResult = protocolParser.doParseProtocol(pretreatmentBuf); + ParseResult parseResult = protocolParser.doParseProtocol(standardByteBuf); //无论什么情况都交给,这里组装的内容,在回复的时候有效使用 list.add(parseResult); } /** + * 此方法废弃,暂做参考使用,byte的使用和帧结构构建例子 + *

* 字节转换成对象 * * @param buffer @@ -58,6 +57,7 @@ * @return * @throws UnsupportedEncodingException */ + @Deprecated private boolean transToMsg(ByteBuf buffer, Msg msg) throws UnsupportedEncodingException { // byte[] bytes=new byte[buffer.readableBytes()]; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java index 54f4c0a..d6bd4bd 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatchSupport.java @@ -1,20 +1,27 @@ package com.casic.missiles.parser.matcher; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.enums.ReplyCommandEnum; import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.parser.GenericProtocolParser; import com.casic.missiles.parser.crc.CRC16; +import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolConfig; import com.casic.missiles.provider.ProtocolFieldConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; /** + * todo: 帧结构匹配支持类 + * * @author cz * @date 2023-7-7 */ -public class FrameStructMatchSupport { +public class FrameStructMatchSupport implements ReplyCommandEnum { /** + * 长度处理核心流程类 + *

* 匹配长度分为以下情况,进行以下情况进行匹配 * 分为加密大于等于,不加密大于等于的情况 * 1、如果有加密方式,则在计算的原业务内容长度与实际长度相比较,如果长度小于实际长度 @@ -49,6 +56,8 @@ } /** + * 长度处理的核心类 + *

* 判断长度时候与指定长度相等,分为当前单包匹配,粘包截取长度匹配,以CRC验证作为整包依据 * 1、相等返回当前的byteBuf * 2、如果大于,进行预判断是否进行粘包,拆取数据帧 @@ -68,12 +77,37 @@ if (crcCheck(preJudgment)) { byteBuf.readerIndex(totalLength); return preJudgment; + } else { + } } return null; } + /** + * 查询匹配位置,进行再次匹配 + * todo: 再次匹配 如何丢弃无法识别的帧, + *

+ * 如果是拆包序列2进入,需要重置byteBuf的读位置,进行重新匹配 + * 匹配布上的数据,如何舍弃帧 + * (1)直接将目前的缓冲池进行清空(最简单) + * (2)用前导集合进行匹配,进行截取丢弃前置无效的内容(情况复杂) + */ + public static ParseResult rematch(ByteBuf byteBuf, GenericProtocolParser genericProtocolParser) { + String oldDataContent = ByteBufUtil.hexDump(byteBuf); + //重置位判断 + byteBuf.resetReaderIndex(); + //判断重置是否前移,如果没有前移,则直接判为匹配失败 + if (oldDataContent.equals(ByteBufUtil.hexDump(byteBuf))) { + return ParseResult.builder().replyCommand(NONE_DATA).build(); + } else { + //递归执行 + return genericProtocolParser.doParseProtocol(byteBuf); + } + } + + public Boolean crcCheck(ByteBuf byteBuf) { String contentHexStr = ByteBufUtil.hexDump(byteBuf); String crcRealValue = contentHexStr.substring(contentHexStr.length() - 4); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java index 4db7175..17dde4f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/FrameStructMatcher.java @@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf; /** + * todo: 通过帧结构,进行帧粘包,截取包、数据完整性等问题的处理 * 分析匹配情况 * 1、匹配成功,直接返回帧结构,截取完整的数据,可以进行下次匹配。 * 2、匹配不成功,有后续帧,可以进行下次匹配。 @@ -12,7 +13,14 @@ */ public interface FrameStructMatcher { - ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); + + /** + * 1、舍弃没有配置帧问题,长度大于数据,进行二次匹配,将前置的废弃帧直接进行丢弃,这个地方和没有匹配到当前协议的处理的方法是同意处理方法 + * 2、处理后续帧粘包的问题 + * + * @return + */ + ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java index e355299..91d7909 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/LeadingCodeMatcher.java @@ -10,11 +10,21 @@ import java.util.Map; import java.util.Set; -public class LeadingCodeMatcher { +/** + * 前导码匹配器 + * + * @author + */ +public class LeadingCodeMatcher{ - //** 帧结构前导码匹配 - // 1、首字母匹配前导码, - // 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + /** + * todo:帧结构前导码匹配 + * 1、首字母匹配前导码, + * 2、以匹配出的前导码是否在报文中条件进行前导码的匹配二次筛选 + * + * @param byteBuf + * @return + */ public static ProtocolConfig matchFrameLeadingCode(ByteBuf byteBuf) { String protocolContent = ByteBufUtil.hexDump(byteBuf); List firstMatchConfigs = initialMatch(protocolContent); @@ -50,14 +60,15 @@ return null; } - /** 默认获取其中使用最多的长度Id - * 1、统计最多长度配置 - * 2、随机选取配置最多的配置 + /** + * 默认获取其中使用最多的长度Id + * 1、统计最多长度配置 + * 2、随机选取配置最多的配置 */ public static CombinedFieldConfig defaultFieldLeadingCode(Map fieldFixedMap) { Set> en = fieldFixedMap.entrySet(); for (Map.Entry entry : en) { - return entry.getValue(); + return entry.getValue(); } //匹配失败 return null; @@ -76,4 +87,5 @@ String beMatchContent = matchContent.substring(0, preFixLength).toLowerCase(); return beMatchContent.equals(preFix.toLowerCase()); } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java index 4927c1e..b53b72d 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameLengthMatcher.java @@ -13,6 +13,9 @@ /** * @author cz + * + * 这里只进行长度与粘包长度的判断 + * */ @Order(0) public class FrameLengthMatcher extends FrameStructMatchSupport implements FrameStructMatcher { @@ -21,7 +24,7 @@ * 超过长度,增加容错长度,同时增加了CRC校验,对帧结构进行判别 */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -45,12 +48,4 @@ return null; } - - private ByteBuf doGetWholeDatagramByte(ByteBuf byteBuf, Integer totalLength) { - byteBuf.readBytes(totalLength); - byteBuf.markReaderIndex();//读的标志位前移 - ByteBuf wholeDatagramByte = byteBuf.slice(0, totalLength - 1); - return wholeDatagramByte; - } - } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java index c4e35c9..a9029c4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameMarkMatcher.java @@ -21,14 +21,21 @@ /** * 后续标志验证 + *

+ * 处理粘包分为以下情况 + * 1、通过后续标志位没有结束,并且继续查询临近帧的时候,没有该数据帧的结束,则进行临时存储,存储时长为当前通道所对应的半小时时长 + * 2、通过后续标志判断为结束,并且序号标记为0,则直接进行解析, + * 如果序号标记不为0,则获取当前通道所对应的储存,查询对应的设备编号的帧,进行排序合并成完整消息的帧。 */ @Order(1) @Slf4j public class FrameMarkMatcher extends FrameStructMatchSupport implements FrameStructMatcher, FixedPropertyEnum { - //帧后续标志=>结束,进行帧的重组=>有后续,1、帧移位判别 2、继续接收帧 + /** + * + */ @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider protocolFieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || protocolFieldConfigProvider == null) { @@ -37,17 +44,19 @@ Integer unpackFlag = ObjectUtils.isEmpty(protocolConfig.getUnpackId()) ? null : protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), byteBuf); ByteBuf intactMessageByte = null; + //暂时实现不进行跳帧的情况,都为临近的帧数据内容 if (!ObjectUtil.isEmpty(unpackFlag)) { - while (hasNextFullFrame(byteBuf, protocolConfig, protocolFieldConfigProvider)) { - //是否存在后续位 + ByteBuf matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); + //取到一个完整的帧 + while (matchByteBuf != null) { + unpackFlag = protocolFieldConfigProvider.getProtocolFieldValue(protocolConfig.getUnpackId(), matchByteBuf); + //后续标志位结束 if (unpackFlag == 1) { //表示可以截取 intactMessageByte = mergeMarkFrame(byteBuf, protocolFieldConfigProvider, protocolConfig, datagramEventConfig); return intactMessageByte; - } else { - byteBuf.readerIndex(byteBuf.readerIndex() + getNextFrameOffset(byteBuf, protocolConfig, protocolFieldConfigProvider)); } - + matchByteBuf = matchLength(byteBuf, datagramEventConfig.getSafeLength(), protocolFactory); } } return null; @@ -94,14 +103,6 @@ } /** - * 获取平移到下一帧起始位置 - */ - public int getNextFrameOffset(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { - Map currentFrameFixedProperty = protocolFieldConfigProvider.getFixedProperty(byteBuf, protocolConfig); - return currentFrameFixedProperty.get(TOTAL_LENGTH); - } - - /** * 判断是否出错进行整个帧的 */ public boolean hasNextFullFrame(ByteBuf byteBuf, ProtocolConfig protocolConfig, ProtocolFieldConfigProvider protocolFieldConfigProvider) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java index b24be0e..0f3adf9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/impl/FrameTailMatcher.java @@ -14,12 +14,16 @@ import org.springframework.core.annotation.Order; import org.springframework.util.ObjectUtils; +/** + * 处理后续标志位 + * 这里对尾部标志位经验较少,可以进行后续扩展增加 + */ @Order(2) public class FrameTailMatcher extends FrameStructMatchSupport implements FrameStructMatcher { //结尾标志位后面还有数据怎么办 @Override - public ByteBuf getWholeDatagram(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { + public ByteBuf getIntactMessageByte(ByteBuf byteBuf, AbstractProtocolConfigFactory protocolFactory, DatagramEventConfig datagramEventConfig) { ProtocolConfig protocolConfig = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig(); ProtocolFieldConfigProvider fieldConfigProvider = protocolFactory.getProtocolFieldConfigProvider(); if (protocolConfig == null || fieldConfigProvider == null) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java new file mode 100644 index 0000000..3620272 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/matcher/store/MatchDataStore.java @@ -0,0 +1,23 @@ +package com.casic.missiles.parser.matcher.store; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; + +import java.util.concurrent.TimeUnit; + +public class MatchDataStore { + + private static ExpiringMap map = ExpiringMap.builder() + + .maxSize(100) + + .expiration(1, TimeUnit.SECONDS) + + .expirationPolicy(ExpirationPolicy.ACCESSED) + + .variableExpiration() + + .build(); + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java deleted file mode 100644 index deca495..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPreProcessing.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import io.netty.buffer.ByteBuf; - -/** - * @author cz - * @date 2023-7-5 - */ -public interface AbstractPreProcessing { - - ByteBuf decode(ByteBuf byteBuf); - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java new file mode 100644 index 0000000..172832c --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/AbstractPretreatment.java @@ -0,0 +1,13 @@ +package com.casic.missiles.parser.predecodec; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + * @date 2023-7-5 + */ +public interface AbstractPretreatment { + + ByteBuf decode(ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java deleted file mode 100644 index e8b72f5..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PreProcessingSupport.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.missiles.parser.predecodec; - -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; - -import java.util.Stack; - -/** - * @author cz - */ -public class PreProcessingSupport { - /** - * 获取第一个大括号,对应的右括号下标值 - * 算法流程 - * 1、初始化totalRightBracket为0 - * 2、获取首个“{”压栈,totalRightBracket加偏移下标 - * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 - * (1)”{“,压栈,totalRightBracket加偏移下标 - * (2)“}”,出栈,totalRightBracket加偏移下标 - * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 - */ - protected Integer getFirstBraceIndex(String detectedContent) { - String tempContent = detectedContent; - Stack stack = new Stack(); - Integer first = detectedContent.indexOf("{"); - Integer totalRightBracket = 0; - totalRightBracket += ++first; - tempContent = tempContent.substring(first); - if (ObjectUtils.isNotEmpty(first)) { - stack.push(first); - while (!stack.isEmpty()) { - if (tempContent.indexOf("{") != -1 && - tempContent.indexOf("}") != -1 - && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { - Integer leftBracket = tempContent.indexOf("{"); - totalRightBracket += ++leftBracket; - tempContent = tempContent.substring(leftBracket); - stack.push(leftBracket); - } else if (tempContent.indexOf("}") != -1) { - Integer rightBracket = tempContent.indexOf("}"); - totalRightBracket += ++rightBracket; - tempContent = tempContent.substring(rightBracket); - stack.pop(); - } else { - return 0; - } - } - return totalRightBracket; - } - return 0; - } - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java new file mode 100644 index 0000000..82b2886 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/PretreatmentSupport.java @@ -0,0 +1,52 @@ +package com.casic.missiles.parser.predecodec; + +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; + +import java.util.Stack; + +/** + * @author cz + */ +public class PretreatmentSupport { + /** + * 获取第一个大括号,对应的右括号下标值 + * 算法流程 + * 1、初始化totalRightBracket为0 + * 2、获取首个“{”压栈,totalRightBracket加偏移下标 + * 3、比较“{”“}”,与最近的单括号(“}””{“),进行一下判断 + * (1)”{“,压栈,totalRightBracket加偏移下标 + * (2)“}”,出栈,totalRightBracket加偏移下标 + * 4、当栈为空时,已经获取到对应的值,返回totalRightBracket的值 + */ + protected Integer getFirstBraceIndex(String detectedContent) { + String tempContent = detectedContent; + Stack stack = new Stack(); + Integer first = detectedContent.indexOf("{"); + Integer totalRightBracket = 0; + totalRightBracket += ++first; + tempContent = tempContent.substring(first); + if (ObjectUtils.isNotEmpty(first)) { + stack.push(first); + while (!stack.isEmpty()) { + if (tempContent.indexOf("{") != -1 && + tempContent.indexOf("}") != -1 + && (tempContent.indexOf("{") < tempContent.indexOf("}"))) { + Integer leftBracket = tempContent.indexOf("{"); + totalRightBracket += ++leftBracket; + tempContent = tempContent.substring(leftBracket); + stack.push(leftBracket); + } else if (tempContent.indexOf("}") != -1) { + Integer rightBracket = tempContent.indexOf("}"); + totalRightBracket += ++rightBracket; + tempContent = tempContent.substring(rightBracket); + stack.pop(); + } else { + return 0; + } + } + return totalRightBracket; + } + return 0; + } + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java deleted file mode 100644 index 20dfa01..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPreProcessing.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.casic.missiles.parser.predecodec.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; -import com.casic.missiles.parser.predecodec.PreProcessingSupport; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.base64.Base64Dialect; -import io.netty.util.internal.ObjectUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.core.annotation.Order; - -import java.nio.charset.Charset; -import java.util.Stack; - -/** - * @description: 将从接口取到的数据编码 - * @author: cz - * @create: 2023-05-04 15:15 - **/ -@Slf4j -@Order(0) -public class AepPreProcessing extends PreProcessingSupport implements AbstractPreProcessing { - - private final Base64Dialect dialect; - - public AepPreProcessing() { - this(Base64Dialect.STANDARD); - } - - public AepPreProcessing(Base64Dialect dialect) { - this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); - } - - //执行nb平台前的协议解析 预处理 - @Override - public ByteBuf decode(ByteBuf msg) { - ByteBuf plaintextBuf = msg; - //aep平台处理 - if (msg.toString(Charset.defaultCharset()).contains("aep")) { - String httpContent = msg.toString(Charset.defaultCharset()); - log.info(" String : " + msg.toString(Charset.defaultCharset())); - try { - //左括号排序,右括号排序,入栈出栈,直接解决问题 - String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); - String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); - String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); - msg.readBytes(firstBraceContent.length()); - msg.markReaderIndex(); - ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); - bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); - plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); - log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); - } catch (Exception ex) { - log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); - } - } - return plaintextBuf; - } - - - - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java new file mode 100644 index 0000000..4898e46 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/AepPretreatment.java @@ -0,0 +1,64 @@ +package com.casic.missiles.parser.predecodec.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; +import com.casic.missiles.parser.predecodec.PretreatmentSupport; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.base64.Base64; +import io.netty.handler.codec.base64.Base64Dialect; +import io.netty.util.internal.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; + +import java.nio.charset.Charset; + +/** + * @description: 将从接口取到的数据编码 + * @author: cz + * @create: 2023-05-04 15:15 + **/ +@Slf4j +@Order(0) +public class AepPretreatment extends PretreatmentSupport implements AbstractPretreatment { + + private final Base64Dialect dialect; + + public AepPretreatment() { + this(Base64Dialect.STANDARD); + } + + public AepPretreatment(Base64Dialect dialect) { + this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); + } + + //执行nb平台前的协议解析 预处理 + @Override + public ByteBuf decode(ByteBuf msg) { + ByteBuf plaintextBuf = msg; + //aep平台处理 + if (msg.toString(Charset.defaultCharset()).contains("aep")) { + String httpContent = msg.toString(Charset.defaultCharset()); + log.info(" String : " + msg.toString(Charset.defaultCharset())); + try { + //左括号排序,右括号排序,入栈出栈,直接解决问题 + String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); + String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); + String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); + msg.readBytes(firstBraceContent.length()); + msg.markReaderIndex(); + ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); + bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); + plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); + log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); + } catch (Exception ex) { + log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); + } + } + return plaintextBuf; + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java deleted file mode 100644 index f43f3aa..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPreProcessing.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.casic.missiles.parser.predecodec.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.predecodec.AbstractPreProcessing; -import com.casic.missiles.parser.predecodec.PreProcessingSupport; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.base64.Base64Dialect; -import io.netty.util.internal.ObjectUtil; -import lombok.extern.slf4j.Slf4j; - -import java.nio.charset.Charset; - -/** - * @author cz - */ -@Slf4j -public class NbPreProcessing extends PreProcessingSupport implements AbstractPreProcessing { - - private final Base64Dialect dialect; - - public NbPreProcessing() { - this(Base64Dialect.STANDARD); - } - - public NbPreProcessing(Base64Dialect dialect) { - this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); - } - - @Override - public ByteBuf decode(ByteBuf msg) { - ByteBuf plaintextBuf = msg; - //aep平台处理 - if (msg.toString(Charset.defaultCharset()).contains("aep")) { - String httpContent = msg.toString(Charset.defaultCharset()); - log.info(" String : " + msg.toString(Charset.defaultCharset())); - try { - //左括号排序,右括号排序,入栈出栈,直接解决问题 - String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); - String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); - String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); - msg.readBytes(firstBraceContent.length()); - msg.markReaderIndex(); - ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); - bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); - plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); - log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); - } catch (Exception ex) { - log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); - } - } - return plaintextBuf; - } - -} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPretreatment.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPretreatment.java new file mode 100644 index 0000000..03fb0e4 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/predecodec/impl/NbPretreatment.java @@ -0,0 +1,58 @@ +package com.casic.missiles.parser.predecodec.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.parser.predecodec.AbstractPretreatment; +import com.casic.missiles.parser.predecodec.PretreatmentSupport; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.base64.Base64; +import io.netty.handler.codec.base64.Base64Dialect; +import io.netty.util.internal.ObjectUtil; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.Charset; + +/** + * @author cz + */ +@Slf4j +public class NbPretreatment extends PretreatmentSupport implements AbstractPretreatment { + + private final Base64Dialect dialect; + + public NbPretreatment() { + this(Base64Dialect.STANDARD); + } + + public NbPretreatment(Base64Dialect dialect) { + this.dialect = ObjectUtil.checkNotNull(dialect, "dialect"); + } + + @Override + public ByteBuf decode(ByteBuf msg) { + ByteBuf plaintextBuf = msg; + //aep平台处理 + if (msg.toString(Charset.defaultCharset()).contains("aep")) { + String httpContent = msg.toString(Charset.defaultCharset()); + log.info(" String : " + msg.toString(Charset.defaultCharset())); + try { + //左括号排序,右括号排序,入栈出栈,直接解决问题 + String firstBraceContent = httpContent.substring(0, getFirstBraceIndex(httpContent)); + String majorContent = firstBraceContent.substring(firstBraceContent.indexOf("{"), firstBraceContent.lastIndexOf("}") + 1); + String values = String.valueOf(((JSONObject) ((JSONObject) JSON.parseObject(majorContent).get("payload")).get("serviceData")).get("Value")); + msg.readBytes(firstBraceContent.length()); + msg.markReaderIndex(); + ByteBuf bufferContent = ByteBufAllocator.DEFAULT.buffer(); + bufferContent.writeBytes(values.getBytes(Charset.forName("ISO-8859-1"))); + plaintextBuf = Base64.decode(bufferContent, bufferContent.readerIndex(), bufferContent.readableBytes(), this.dialect); + log.debug(ByteBufUtil.hexDump(msg) + "---------------------------------" + ByteBufUtil.hexDump(plaintextBuf)); + } catch (Exception ex) { + log.info("AEP平台解码出现异常,缓存池为{},异常信息为{}", ByteBufUtil.hexDump(msg), ex); + } + } + return plaintextBuf; + } + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index a52aceb..3d5cc26 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -14,10 +14,13 @@ public class SensorhubReplier extends SimpleChannelInboundHandler { /** - * 回复分为一下情况 - * 1、成功返回时间 - * 2、如果有下发配置,下发配置(组建配置) - * 3、版本升级,下位机下发版本,是否升级,是上版本,是升级,请求,回复升级等流程 + * 该类方法是回复内容构建的流程入口类 + * 1、通过有标准协议解析器传来的结果进行命令的构建 + * 2、构建命令有以下的命令内容 + * (1)成功返回时间,并进行下发配置操作 + * (2)版本升级 + * (3)下位机下发版本是否升级,是上版本,是升级,请求,回复升级等流程 + * (4)其他未知需求命令 */ @Override public void channelRead0(ChannelHandlerContext ctx, Object obj) throws Exception { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index f5b5613..5616e16 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -25,7 +25,8 @@ public class DataReplyCommand extends ReplyCommandSupport implements AbstractBuildReplyCommand { /** - * 构建流程如下: + * 成功解析帧结构内容,进行下发成功回复命令的主要流程方法 + *其构建流程逻辑如下: * 1、初始化反构配置 * 2、进行业务内容的构建 * (1)默认为时间的构建 diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java index fdb6c81..b22a8b3 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java @@ -29,9 +29,10 @@ /** - * 完整的数组操作 - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 + * todo: 组合字段的报文构建 + * (1) 处理前导字段的反构 + * (2)处理长度字段的反构 + * (3)将核心字段的反构,交给解析器进行反构 */ public static ByteBuf combinedField(Map fieldConfigsMap, CombinedFieldConfig combinedFieldConfig, Object filedValue) {