diff --git a/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCDataProtocol.java b/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCDataProtocol.java index 67de4b837..861c2c229 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCDataProtocol.java +++ b/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCDataProtocol.java @@ -61,13 +61,20 @@ public class YKCDataProtocol { this.crcByte = new byte[]{msg[msg.length - 2], msg[msg.length - 1]}; } + /** + * 获取字节数组 + */ + public byte[] getBytes() { + return Bytes.concat(this.head, this.length, this.serialNumber, this.encryptFlag, this.frameType, this.msgBody, this.crcByte); + } + /** * 转换为十六进制字符串 * * @return 报文 */ public String getHEXString() { - byte[] bytes = Bytes.concat(this.head, this.length, this.serialNumber, this.encryptFlag, this.frameType, this.msgBody, this.crcByte); + byte[] bytes = getBytes(); return BytesUtil.binary(bytes, 16); } } diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/CRC16Util.java b/jsowell-common/src/main/java/com/jsowell/common/util/CRC16Util.java index eceb4753f..b2ef04ec0 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/util/CRC16Util.java +++ b/jsowell-common/src/main/java/com/jsowell/common/util/CRC16Util.java @@ -186,6 +186,20 @@ public class CRC16Util { /*以下方法得出的校验位:低位在前,高位在后*/ + public static short calculateCrc(short serialNumber, byte encryptFlag, byte frameType, byte[] messageBody) { + // short serialNumber 转byte[] + byte[] serialNumberBytes = new byte[2]; + // byte encryptFlag 转byte[] + byte[] encryptFlagBytes = new byte[1]; + // byte frameType 转byte[] + byte[] frameTypeBytes = new byte[1]; + // byte[] messageBody 转byte[] + // 序列号域+加密标志+帧类型标志+消息体 + byte[] data = Bytes.concat(serialNumberBytes, encryptFlagBytes, frameTypeBytes, messageBody); + int i = calcCrc16(data); + return (short) i; + } + /** * @param data 需要计算的数组 * @return CRC16校验值 diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/YKCUtils.java b/jsowell-common/src/main/java/com/jsowell/common/util/YKCUtils.java index ff345ecb4..f96ee1580 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/util/YKCUtils.java +++ b/jsowell-common/src/main/java/com/jsowell/common/util/YKCUtils.java @@ -52,6 +52,13 @@ public class YKCUtils { log.error("起始位必须是0x68"); return false; } + + // 如果是0x03帧,则不进行crc校验 + if (0x03 == frameType[0]) { + log.info("0x03帧,则不进行crc校验"); + return true; + } + // 序列号域+加密标志+帧类型标志+消息体 byte[] data = Bytes.concat(serialNumber, encryptFlag, frameType, msgBody); // 校验长度 @@ -77,6 +84,60 @@ public class YKCUtils { return false; } + public static boolean checkMsg(YKCDataProtocol ykcDataProtocol) { + // log.info("checkMsg:{}", BytesUtil.binary(msg, 16)); + // 起始标志 + byte[] head = ykcDataProtocol.getHead(); + // 数据长度 + byte[] length = ykcDataProtocol.getLength(); + // 序列号域 + byte[] serialNumber = ykcDataProtocol.getSerialNumber(); + // 加密标志 + byte[] encryptFlag = ykcDataProtocol.getEncryptFlag(); + // 帧类型标志 + byte[] frameType = ykcDataProtocol.getFrameType(); + // 消息体 + byte[] msgBody = ykcDataProtocol.getMsgBody(); + // 帧校验域 + byte[] crcByte = ykcDataProtocol.getCrcByte(); + + //起始位必须是0x68 + if (0x68 != head[0]) { + log.error("起始位必须是0x68"); + return false; + } + + // 如果是0x03帧,则不进行crc校验 + if (0x03 == frameType[0]) { + log.info("0x03帧,则不进行crc校验"); + return true; + } + + // 序列号域+加密标志+帧类型标志+消息体 + byte[] data = Bytes.concat(serialNumber, encryptFlag, frameType, msgBody); + // 校验长度 + if (data.length != BytesUtil.bytesToIntLittle(length)) { + log.error("数据长度不正确, 数据长度:{}, 实际长度:{}", BytesUtil.bytesToIntLittle(length), data.length); + return false; + } + // CRC校验 source target + String sourceCRC = String.format("%04x", BytesUtil.bytesToInt(crcByte, 0)); + String targetCRC = String.format("%04x", CRC16Util.calcCrc16(data)); + String oldTargetCRC = String.format("%04x", CRC16Util.calcCrc16Old(data)); + // 将高低位位置反转,得出新的crc + String lowString = StringUtils.substring(targetCRC, 0, 2); + String highString = StringUtils.substring(targetCRC, 2, 4); + String crc = highString + lowString; + // 若目标crc和高低位反转前/后的crc都不一致,则校验不通过 + if (sourceCRC.equalsIgnoreCase(targetCRC) || sourceCRC.equalsIgnoreCase(crc)) { + return true; + } + log.error("CRC校验不通过, 源crc:{}, 计算得出crc:{}, 老crc计算:{}, 高低位反转后crc:{}, 帧类型:{}, 帧名称:{}, 报文:{}" + , sourceCRC, targetCRC, oldTargetCRC, crc, YKCUtils.frameType2Str(frameType), + YKCFrameTypeCode.getFrameTypeStr(YKCUtils.frameType2Str(frameType)), BytesUtil.binary(ykcDataProtocol.getBytes(), 16)); + return false; + } + /** * 获取结果报文 * @param ykcDataProtocol diff --git a/jsowell-netty/src/main/java/com/jsowell/netty/decoder/YkcProtocolDecoder.java b/jsowell-netty/src/main/java/com/jsowell/netty/decoder/YkcProtocolDecoder.java new file mode 100644 index 000000000..b34136d2f --- /dev/null +++ b/jsowell-netty/src/main/java/com/jsowell/netty/decoder/YkcProtocolDecoder.java @@ -0,0 +1,105 @@ +package com.jsowell.netty.decoder; + +import com.jsowell.common.util.BytesUtil; +import com.jsowell.common.util.CRC16Util; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import io.netty.handler.codec.DecoderException; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +@Slf4j +public class YkcProtocolDecoder extends ByteToMessageDecoder { + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + log.info("YkcProtocolDecoder.decode"); + // 检查起始标志是否为0x68 + if (in.readableBytes() < 5) { + return; // 至少需要 起始标志 (1) + 数据长度 (1) + 序列号域 (2) + 帧校验域 (1) + } + + in.markReaderIndex(); // 标记当前读取位置 + byte startFlag = in.readByte(); + log.info("startFlag: {}", BytesUtil.binary(new byte[]{startFlag}, 16)); + if (startFlag != (byte) 0x68) { + throw new DecoderException("Invalid start flag: " + startFlag); + } + + // 读取数据长度 + byte dataLength = in.readByte(); + if (in.readableBytes() < dataLength + 2) { // 消息体 + 帧校验域长度 + in.resetReaderIndex(); + return; // 数据不足,等待更多字节 + } + + // 读取其他字段 + short serialNumber = in.readShort(); // 序列号域 + log.info("serialNumber: {}", BytesUtil.printHexBinary(new byte[]{(byte) serialNumber})); + byte encryptFlag = in.readByte(); // 加密标志 + log.info("encryptFlag: {}", BytesUtil.printHexBinary(new byte[]{encryptFlag})); + byte frameType = in.readByte(); // 帧类型标志 + log.info("frameType: {}", BytesUtil.printHexBinary(new byte[]{frameType})); + + // 读取消息体 + byte[] messageBody = new byte[dataLength - 4]; // 消息体长度 = 数据长度 - 固定字段长度 + log.info("messageBody: {}", BytesUtil.printHexBinary(messageBody)); + in.readBytes(messageBody); + + // 读取帧校验域 + short receivedCrc = in.readShort(); + + // 计算 CRC + short calculatedCrc = CRC16Util.calculateCrc(serialNumber, encryptFlag, frameType, messageBody); + if (calculatedCrc != receivedCrc) { + throw new DecoderException("CRC check failed. Expected: " + receivedCrc + ", Calculated: " + calculatedCrc); + } + + // 构造消息对象并传递给下一个处理器 + ProtocolMessage message = new ProtocolMessage(startFlag, dataLength, serialNumber, encryptFlag, frameType, messageBody, receivedCrc); + out.add(message); + } + + public static int bcdToDecimal(byte bcd1, byte bcd2) { + // BCD码转换为十进制 + int high = (bcd1 >> 4) & 0x0F; // 高4位 + int low = bcd1 & 0x0F; // 低4位 + int high2 = (bcd2 >> 4) & 0x0F; + int low2 = bcd2 & 0x0F; + + // 将BCD码拼接成十进制数 + return (high * 1000) + (low * 100) + (high2 * 10) + low2; + } + + // 自定义消息类 + public static class ProtocolMessage { + private final byte startFlag; + private final byte dataLength; + private final short serialNumber; + private final byte encryptFlag; + private final byte frameType; + private final byte[] messageBody; + private final short crc; + + public ProtocolMessage(byte startFlag, byte dataLength, short serialNumber, byte encryptFlag, byte frameType, byte[] messageBody, short crc) { + this.startFlag = startFlag; + this.dataLength = dataLength; + this.serialNumber = serialNumber; + this.encryptFlag = encryptFlag; + this.frameType = frameType; + this.messageBody = messageBody; + this.crc = crc; + } + + // Getter methods... + public byte getStartFlag() { return startFlag; } + public byte getDataLength() { return dataLength; } + public short getSerialNumber() { return serialNumber; } + public byte getEncryptFlag() { return encryptFlag; } + public byte getFrameType() { return frameType; } + public byte[] getMessageBody() { return messageBody; } + public short getCrc() { return crc; } + } +} diff --git a/jsowell-netty/src/main/java/com/jsowell/netty/decoder/YouDianProtocolDecoder.java b/jsowell-netty/src/main/java/com/jsowell/netty/decoder/YouDianProtocolDecoder.java new file mode 100644 index 000000000..c38ebef1f --- /dev/null +++ b/jsowell-netty/src/main/java/com/jsowell/netty/decoder/YouDianProtocolDecoder.java @@ -0,0 +1,141 @@ +package com.jsowell.netty.decoder; + +import com.jsowell.common.constant.Constants; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + * 友电协议解码器 + */ +@Slf4j +public class YouDianProtocolDecoder extends ByteToMessageDecoder { + private static final int HEADER_LENGTH_DNY = 3; // "DNY" 包头的长度 + private static final int HEADER_LENGTH_68 = 1; // 68 包头的长度 + + // 构造函数,初始化起始标志 + public YouDianProtocolDecoder() {} + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws Exception { + // log.info("StartAndLengthFieldFrameDecoder.decode"); + // 记录包头开始的index + int beginReader; + + // 循环查找包头 + while (true) { + if (buffer.readableBytes() < Math.min(HEADER_LENGTH_DNY, HEADER_LENGTH_68)) { + return; // 数据长度不足,等待更多数据 + } + + // 获取包头开始的index + beginReader = buffer.readerIndex(); + buffer.markReaderIndex(); + + // 判断是否为DNY包头或68包头 + if (isStartOfDnyHeader(buffer, beginReader) || isStartOf68Header(buffer, beginReader)) { + break; // 读到了协议的开始标志,结束while循环 + } + + // 未读到包头,略过一个字节 + buffer.resetReaderIndex(); + buffer.readByte(); + } + + // 检查包头是否是 "DNY" + if (buffer.readableBytes() >= HEADER_LENGTH_DNY) { + byte[] headerBytes = new byte[HEADER_LENGTH_DNY]; + buffer.getBytes(beginReader, headerBytes, 0, HEADER_LENGTH_DNY); + String header = new String(headerBytes, StandardCharsets.UTF_8); + // log.info("检查包头是否是DNY, header:{}", header); + if (Constants.EBIKE_HEADER.equals(header)) { + // 处理 DNY 协议 + decodeDnyMessage(buffer, out, beginReader); + return; + } + } + + // 检查包头是否是 68 协议 + if (buffer.readableBytes() >= HEADER_LENGTH_68) { + if (buffer.getUnsignedByte(beginReader) == 0x68) { + // 处理 68 协议 + decode68Message(buffer, out, beginReader); + return; + } + } + + // 未知协议,还原读指针 + buffer.resetReaderIndex(); + } + + // 判断是否为DNY包头 + private boolean isStartOfDnyHeader(ByteBuf buffer, int beginReader) { + if (buffer.readableBytes() >= HEADER_LENGTH_DNY) { + byte[] headerBytes = new byte[HEADER_LENGTH_DNY]; + buffer.getBytes(beginReader, headerBytes, 0, HEADER_LENGTH_DNY); + String header = new String(headerBytes, StandardCharsets.UTF_8); + return Constants.EBIKE_HEADER.equals(header); + } + return false; + } + + // 判断是否为68包头 + private boolean isStartOf68Header(ByteBuf buffer, int beginReader) { + if (buffer.readableBytes() >= HEADER_LENGTH_68) { + return buffer.getUnsignedByte(beginReader) == 0x68; + } + return false; + } + + // 处理68协议消息 + private void decode68Message(ByteBuf buffer, List out, int beginReader) { + // 检查剩余数据是否足够 + if (buffer.readableBytes() < HEADER_LENGTH_68 + 1 + 2) { + buffer.readerIndex(beginReader); + return; + } + + // 获取消息长度 + int length = buffer.getUnsignedByte(beginReader + HEADER_LENGTH_68); + // 检查剩余数据是否足够 + if (buffer.readableBytes() < HEADER_LENGTH_68 + 1 + length + 2) { + buffer.readerIndex(beginReader); + return; + } + + // 读取 data 数据 最后+2是帧校验域长度 + ByteBuf frame = buffer.retainedSlice(beginReader, HEADER_LENGTH_68 + 1 + length + 2); + buffer.readerIndex(beginReader + HEADER_LENGTH_68 + 1 + length + 2); + out.add(frame); + } + + // 处理DNY协议消息 + private void decodeDnyMessage(ByteBuf buffer, List out, int beginReader) { + // 检查剩余数据是否足够 + if (buffer.readableBytes() < HEADER_LENGTH_DNY + 1) { + buffer.readerIndex(beginReader); + return; + } + + // 获取消息长度 + int length = buffer.getUnsignedByte(beginReader + HEADER_LENGTH_DNY); + // log.info("获取消息长度, length:{}", length); + // 检查剩余数据是否足够 + if (buffer.readableBytes() < HEADER_LENGTH_DNY + 1 + length) { + buffer.readerIndex(beginReader); + return; + } + + // 读取 data 数据 + ByteBuf frame = buffer.retainedSlice(beginReader, HEADER_LENGTH_DNY + length + 2); + buffer.readerIndex(beginReader + HEADER_LENGTH_DNY + length + 2); + + + out.add(frame); + } + +} diff --git a/jsowell-netty/src/main/java/com/jsowell/netty/decoder/YunKuaiChongDecoder.java b/jsowell-netty/src/main/java/com/jsowell/netty/decoder/YunKuaiChongDecoder.java new file mode 100644 index 000000000..8841b1dd0 --- /dev/null +++ b/jsowell-netty/src/main/java/com/jsowell/netty/decoder/YunKuaiChongDecoder.java @@ -0,0 +1,144 @@ +package com.jsowell.netty.decoder; + +import com.jsowell.common.constant.Constants; +import com.jsowell.common.core.domain.ykc.YKCDataProtocol; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +@Slf4j +public class YunKuaiChongDecoder extends ByteToMessageDecoder { + private static final int HEADER_LENGTH_DNY = 3; // "DNY" 包头的长度 + private static final int HEADER_LENGTH_68 = 1; // 68 包头的长度 + + // 构造函数,初始化起始标志 + public YunKuaiChongDecoder() {} + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws Exception { + // log.info("StartAndLengthFieldFrameDecoder.decode"); + // 记录包头开始的index + int beginReader; + + // 循环查找包头 + while (true) { + if (buffer.readableBytes() < Math.min(HEADER_LENGTH_DNY, HEADER_LENGTH_68)) { + return; // 数据长度不足,等待更多数据 + } + + // 获取包头开始的index + beginReader = buffer.readerIndex(); + buffer.markReaderIndex(); + + // 判断是否为DNY包头或68包头 + if (isStartOfDnyHeader(buffer, beginReader) || isStartOf68Header(buffer, beginReader)) { + break; // 读到了协议的开始标志,结束while循环 + } + + // 未读到包头,略过一个字节 + buffer.resetReaderIndex(); + buffer.readByte(); + } + + // 检查包头是否是 "DNY" + if (buffer.readableBytes() >= HEADER_LENGTH_DNY) { + byte[] headerBytes = new byte[HEADER_LENGTH_DNY]; + buffer.getBytes(beginReader, headerBytes, 0, HEADER_LENGTH_DNY); + String header = new String(headerBytes, StandardCharsets.UTF_8); + // log.info("检查包头是否是DNY, header:{}", header); + if (Constants.EBIKE_HEADER.equals(header)) { + // 处理 DNY 协议 + decodeDnyMessage(buffer, out, beginReader); + return; + } + } + + // 检查包头是否是 68 协议 + if (buffer.readableBytes() >= HEADER_LENGTH_68) { + if (buffer.getUnsignedByte(beginReader) == 0x68) { + // 处理 68 协议 + decode68Message(buffer, out, beginReader); + return; + } + } + + // 未知协议,还原读指针 + buffer.resetReaderIndex(); + } + + // 判断是否为DNY包头 + private boolean isStartOfDnyHeader(ByteBuf buffer, int beginReader) { + if (buffer.readableBytes() >= HEADER_LENGTH_DNY) { + byte[] headerBytes = new byte[HEADER_LENGTH_DNY]; + buffer.getBytes(beginReader, headerBytes, 0, HEADER_LENGTH_DNY); + String header = new String(headerBytes, StandardCharsets.UTF_8); + return Constants.EBIKE_HEADER.equals(header); + } + return false; + } + + // 判断是否为68包头 + private boolean isStartOf68Header(ByteBuf buffer, int beginReader) { + if (buffer.readableBytes() >= HEADER_LENGTH_68) { + return buffer.getUnsignedByte(beginReader) == 0x68; + } + return false; + } + + // 处理68协议消息 + private void decode68Message(ByteBuf buffer, List out, int beginReader) { + // 检查剩余数据是否足够 + if (buffer.readableBytes() < HEADER_LENGTH_68 + 1 + 2) { + buffer.readerIndex(beginReader); + return; + } + + // 获取消息长度 + int length = buffer.getUnsignedByte(beginReader + HEADER_LENGTH_68); + // 检查剩余数据是否足够 + if (buffer.readableBytes() < HEADER_LENGTH_68 + 1 + length + 2) { + buffer.readerIndex(beginReader); + return; + } + + // 读取 data 数据 最后+2是帧校验域长度 + ByteBuf frame = buffer.retainedSlice(beginReader, HEADER_LENGTH_68 + 1 + length + 2); + buffer.readerIndex(beginReader + HEADER_LENGTH_68 + 1 + length + 2); + + // 转为YKCDataProtocol对象 + byte[] bytes = new byte[HEADER_LENGTH_68 + 1 + length + 2]; + frame.readBytes(bytes); + YKCDataProtocol ykcDataProtocol = new YKCDataProtocol(bytes); + out.add(ykcDataProtocol); + } + + // 处理DNY协议消息 + private void decodeDnyMessage(ByteBuf buffer, List out, int beginReader) { + // 检查剩余数据是否足够 + if (buffer.readableBytes() < HEADER_LENGTH_DNY + 1) { + buffer.readerIndex(beginReader); + return; + } + + // 获取消息长度 + int length = buffer.getUnsignedByte(beginReader + HEADER_LENGTH_DNY); + // log.info("获取消息长度, length:{}", length); + // 检查剩余数据是否足够 + if (buffer.readableBytes() < HEADER_LENGTH_DNY + 1 + length) { + buffer.readerIndex(beginReader); + return; + } + + // 读取 data 数据 + ByteBuf frame = buffer.retainedSlice(beginReader, HEADER_LENGTH_DNY + length + 2); + buffer.readerIndex(beginReader + HEADER_LENGTH_DNY + length + 2); + + + out.add(frame); + } + +} diff --git a/jsowell-netty/src/main/java/com/jsowell/netty/server/electricbicycles/ElectricBicyclesServerChannelInitializer.java b/jsowell-netty/src/main/java/com/jsowell/netty/server/electricbicycles/ElectricBicyclesServerChannelInitializer.java index 4e4cb6edc..3b9ef4631 100644 --- a/jsowell-netty/src/main/java/com/jsowell/netty/server/electricbicycles/ElectricBicyclesServerChannelInitializer.java +++ b/jsowell-netty/src/main/java/com/jsowell/netty/server/electricbicycles/ElectricBicyclesServerChannelInitializer.java @@ -1,6 +1,6 @@ package com.jsowell.netty.server.electricbicycles; -import com.jsowell.netty.decoder.StartAndLengthFieldFrameDecoder; +import com.jsowell.netty.decoder.YouDianProtocolDecoder; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -20,7 +20,7 @@ public class ElectricBicyclesServerChannelInitializer extends ChannelInitializer @Override protected void initChannel(SocketChannel channel) throws Exception { ChannelPipeline pipeline = channel.pipeline(); - pipeline.addLast("frameDecoder", new StartAndLengthFieldFrameDecoder()); + pipeline.addLast("frameDecoder", new YouDianProtocolDecoder()); // pipeline.addLast("decoder", new MessageDecode()); // pipeline.addLast("encoder", new MessageEncode()); pipeline.addLast("decoder", new ByteArrayDecoder()); diff --git a/jsowell-netty/src/main/java/com/jsowell/netty/server/yunkuaichong/NettyServerChannelInitializer.java b/jsowell-netty/src/main/java/com/jsowell/netty/server/yunkuaichong/NettyServerChannelInitializer.java index 6dbace035..4db0989f3 100644 --- a/jsowell-netty/src/main/java/com/jsowell/netty/server/yunkuaichong/NettyServerChannelInitializer.java +++ b/jsowell-netty/src/main/java/com/jsowell/netty/server/yunkuaichong/NettyServerChannelInitializer.java @@ -1,6 +1,6 @@ package com.jsowell.netty.server.yunkuaichong; -import com.jsowell.netty.decoder.CustomLengthFieldBasedFrameDecoder; +import com.jsowell.netty.decoder.YunKuaiChongDecoder; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -22,7 +22,8 @@ public class NettyServerChannelInitializer extends ChannelInitializer>>>>平台响应消息>>>>>】channel:{}, 响应帧类型:{}, 响应帧名称:{}, 原帧类型:{}, 原帧名称:{}, 序列号域:{}, response:{}", + // channel.id(), responseFrameType, YKCFrameTypeCode.getFrameTypeStr(responseFrameType), + // frameType, YKCFrameTypeCode.getFrameTypeStr(frameType), serialNumber, + // BytesUtil.binary(response, 16)); + // } + // } + // } + @Override public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception { - // log.info("加载客户端报文channelRead=== channelId:" + ctx.channel().id() + ", msg:" + message); - // 下面可以解析数据,保存数据,生成返回报文,将需要返回报文写入write函数 - byte[] msg = (byte[]) message; + YKCDataProtocol ykcDataProtocol = (YKCDataProtocol) message; // 获取帧类型 - byte[] frameTypeBytes = BytesUtil.copyBytes(msg, 5, 1); + byte[] frameTypeBytes = ykcDataProtocol.getFrameType(); String frameType = YKCUtils.frameType2Str(frameTypeBytes); // 判断该帧类型是否为某请求帧的应答帧 @@ -86,7 +145,7 @@ public class NettyServerHandler extends ChannelInboundHandlerAdapter { SyncPromise syncPromise = RpcUtil.getSyncPromiseMap().get(msgId); if(syncPromise != null) { // 设置响应结果 - syncPromise.setRpcResult(msg); + syncPromise.setRpcResult(ykcDataProtocol.getBytes()); // 唤醒外部线程 // log.info("同步获取响应数据-唤醒外部线程, SyncPromise:{}", JSON.toJSONString(syncPromise)); syncPromise.wake(); @@ -94,7 +153,7 @@ public class NettyServerHandler extends ChannelInboundHandlerAdapter { } // 获取序列号域 - int serialNumber = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(msg, 2, 2)); + int serialNumber = BytesUtil.bytesToIntLittle(ykcDataProtocol.getSerialNumber()); // 获取channel Channel channel = ctx.channel(); @@ -103,11 +162,11 @@ public class NettyServerHandler extends ChannelInboundHandlerAdapter { if (!CollectionUtils.containsAny(notPrintFrameTypeList, frameType)) { log.info("【<<<<<平台收到消息<<<<<】channel:{}, 帧类型:{}, 帧名称:{}, 序列号域:{}, 报文:{}", channel.id(), frameType, YKCFrameTypeCode.getFrameTypeStr(frameType), serialNumber, - BytesUtil.binary(msg, 16)); + BytesUtil.binary(ykcDataProtocol.getBytes(), 16)); } // 处理数据 - byte[] response = ykcService.process(msg, ctx); + byte[] response = ykcService.process(ykcDataProtocol, ctx); if (Objects.nonNull(response)) { // 响应客户端 ByteBuf buffer = ctx.alloc().buffer().writeBytes(response); diff --git a/jsowell-netty/src/main/java/com/jsowell/netty/service/yunkuaichong/YKCBusinessService.java b/jsowell-netty/src/main/java/com/jsowell/netty/service/yunkuaichong/YKCBusinessService.java index 102ac12fc..1bf85a02b 100644 --- a/jsowell-netty/src/main/java/com/jsowell/netty/service/yunkuaichong/YKCBusinessService.java +++ b/jsowell-netty/src/main/java/com/jsowell/netty/service/yunkuaichong/YKCBusinessService.java @@ -1,6 +1,6 @@ package com.jsowell.netty.service.yunkuaichong; -import io.netty.channel.Channel; +import com.jsowell.common.core.domain.ykc.YKCDataProtocol; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelId; @@ -18,6 +18,8 @@ public interface YKCBusinessService { */ byte[] process(byte[] msg, ChannelHandlerContext ctx); + byte[] process(YKCDataProtocol ykcDataProtocol, ChannelHandlerContext ctx); + /** * 桩退出 * @param channelId channelId diff --git a/jsowell-netty/src/main/java/com/jsowell/netty/service/yunkuaichong/impl/YKCBusinessServiceImpl.java b/jsowell-netty/src/main/java/com/jsowell/netty/service/yunkuaichong/impl/YKCBusinessServiceImpl.java index 4c5e341a8..0ba47582b 100644 --- a/jsowell-netty/src/main/java/com/jsowell/netty/service/yunkuaichong/impl/YKCBusinessServiceImpl.java +++ b/jsowell-netty/src/main/java/com/jsowell/netty/service/yunkuaichong/impl/YKCBusinessServiceImpl.java @@ -49,6 +49,20 @@ public class YKCBusinessServiceImpl implements YKCBusinessService { return invokeStrategy.supplyProcess(ykcDataProtocol, ctx); } + @Override + public byte[] process(YKCDataProtocol ykcDataProtocol, ChannelHandlerContext ctx) { + if (!YKCUtils.checkMsg(ykcDataProtocol)) { + // 校验不通过,丢弃消息 + return null; + } + // 获取帧类型 + String frameType = YKCUtils.frameType2Str(ykcDataProtocol.getFrameType()); + // 获取业务处理handler + AbstractYkcHandler invokeStrategy = YKCOperateFactory.getInvokeStrategy(frameType); + // AbstractYkcHandlerV2 invokeStrategy = ykcOperateFactoryV2.getInvokeStrategy(frameType); + return invokeStrategy.supplyProcess(ykcDataProtocol, ctx); + } + @Override public void exit(ChannelId channelId) { // 获取桩编号 diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/platform/service/impl/GanSuPlatformServiceImpl.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/platform/service/impl/GanSuPlatformServiceImpl.java index 173295015..776cc5c73 100644 --- a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/platform/service/impl/GanSuPlatformServiceImpl.java +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/platform/service/impl/GanSuPlatformServiceImpl.java @@ -186,8 +186,6 @@ public class GanSuPlatformServiceImpl implements ThirdPartyPlatformService { .stationLat(new BigDecimal(pileStationInfo.getStationLat())) .construction(Integer.parseInt(pileStationInfo.getConstruction())) .parkNums(Integer.parseInt(pileStationInfo.getParkNums())) - // todo .electricityFee() - // todo .serviceFee() .build(); JSONObject electricityFee = new JSONObject(); @@ -440,6 +438,7 @@ public class GanSuPlatformServiceImpl implements ThirdPartyPlatformService { if (StringUtils.isBlank(token)) { return null; } + // 调用联联平台接口 String jsonString = JSON.toJSONString(chargeOrderInfo); String result = HttpRequestUtil.sendPost(token, jsonString, url, dataSecret, dataSecretIv, operatorId, signSecret);