diff --git a/jsowell-netty/src/main/java/com/jsowell/netty/decoder/ProtocolDnyDecoder.java b/jsowell-netty/src/main/java/com/jsowell/netty/decoder/ProtocolDnyDecoder.java new file mode 100644 index 000000000..0c627aab7 --- /dev/null +++ b/jsowell-netty/src/main/java/com/jsowell/netty/decoder/ProtocolDnyDecoder.java @@ -0,0 +1,117 @@ +package com.jsowell.netty.decoder; + + +import com.jsowell.netty.domain.ProtocolDnyMessage; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import lombok.extern.slf4j.Slf4j; + +import java.nio.ByteOrder; +import java.util.List; + +@Slf4j +public class ProtocolDnyDecoder extends ByteToMessageDecoder { + private static final int HEADER_LENGTH = 3; // 包头长度 + private static final int LENGTH_FIELD_LENGTH = 2; // 长度字段长度 + private static final int PHYSICAL_ID_LENGTH = 4; // 物理ID长度 + private static final int MESSAGE_ID_LENGTH = 2; // 消息ID长度 + private static final int COMMAND_LENGTH = 1; // 命令长度 + private static final int CHECKSUM_LENGTH = 2; // 校验字段长度 + + private static final int MIN_FRAME_LENGTH = HEADER_LENGTH + LENGTH_FIELD_LENGTH + PHYSICAL_ID_LENGTH + MESSAGE_ID_LENGTH + COMMAND_LENGTH + CHECKSUM_LENGTH; + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + // 检查是否有足够的数据来读取最小帧长度 + if (in.readableBytes() < MIN_FRAME_LENGTH) { + return; + } + + // 标记当前读位置 + in.markReaderIndex(); + + // 检查包头 + byte[] header = new byte[HEADER_LENGTH]; + in.readBytes(header); + if (header[0] != 'D' || header[1] != 'N' || header[2] != 'Y') { + in.resetReaderIndex(); + throw new IllegalStateException("Invalid start bytes: " + new String(header)); + } + + // 读取长度字段 + in.order(ByteOrder.LITTLE_ENDIAN); // 确保使用小端模式 + int length = in.readUnsignedShort(); + if (in.readableBytes() < length) { + in.resetReaderIndex(); + return; + } + + // 读取物理ID + byte[] physicalId = new byte[PHYSICAL_ID_LENGTH]; + in.readBytes(physicalId); + + // 读取消息ID + int messageId = in.readUnsignedShort(); + + // 读取命令 + byte command = in.readByte(); + + // 读取数据 + int dataLength = length - (PHYSICAL_ID_LENGTH + MESSAGE_ID_LENGTH + COMMAND_LENGTH + CHECKSUM_LENGTH); + byte[] data = new byte[dataLength]; + in.readBytes(data); + + // 读取校验字段 + int checksum = in.readUnsignedShort(); + + // 计算校验值并验证 + if (!verifyChecksum(header, length, physicalId, messageId, command, data, checksum)) { + in.resetReaderIndex(); + throw new IllegalStateException("Invalid checksum"); + } + + // 创建协议消息对象 + ProtocolDnyMessage message = new ProtocolDnyMessage(header, length, physicalId, messageId, command, data, checksum); + + // 将解码后的消息添加到输出列表中 + out.add(message); + } + + // 校验帧校验域的函数 + private boolean verifyChecksum(byte[] header, int length, byte[] physicalId, int messageId, byte command, byte[] data, int checksum) { + // 这里需要实现校验逻辑,假设我们有一个累加和校验函数sumCheck + int calculatedChecksum = sumCheck(header, length, physicalId, messageId, command, data); + return calculatedChecksum == checksum; + } + + // 累加和校验函数,计算从包头到数据的累加和 + private int sumCheck(byte[] header, int length, byte[] physicalId, int messageId, byte command, byte[] data) { + int sum = 0; + + for (byte b : header) { + sum += b & 0xFF; + } + + sum += length & 0xFF; + sum += (length >> 8) & 0xFF; + + for (byte b : physicalId) { + sum += b & 0xFF; + } + + sum += messageId & 0xFF; + sum += (messageId >> 8) & 0xFF; + + sum += command & 0xFF; + + for (byte b : data) { + sum += b & 0xFF; + } + + return sum & 0xFFFF; // 返回16位结果 + } +} + + + diff --git a/jsowell-netty/src/main/java/com/jsowell/netty/decoder/StartAndLengthFieldFrameDecoder.java b/jsowell-netty/src/main/java/com/jsowell/netty/decoder/StartAndLengthFieldFrameDecoder.java index 33120b951..5cf54c4c3 100644 --- a/jsowell-netty/src/main/java/com/jsowell/netty/decoder/StartAndLengthFieldFrameDecoder.java +++ b/jsowell-netty/src/main/java/com/jsowell/netty/decoder/StartAndLengthFieldFrameDecoder.java @@ -13,6 +13,9 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder { private static final int HEADER_LENGTH_DNY = 3; // "DNY" 包头的长度 private static final int HEADER_LENGTH_68 = 1; // 68 包头的长度 + // 构造函数,初始化起始标志 + public StartAndLengthFieldFrameDecoder() {} + // 起始标志 // private int HEAD_DATA; @@ -88,6 +91,7 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder { // 记录包头开始的index int beginReader; + // 循环查找包头 while (true) { if (buffer.readableBytes() < Math.min(HEADER_LENGTH_DNY, HEADER_LENGTH_68)) { return; // 数据长度不足,等待更多数据 @@ -102,9 +106,9 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder { // break; // } - // 读到了协议的开始标志,结束while循环 + // 判断是否为DNY包头或68包头 if (isStartOfDnyHeader(buffer, beginReader) || isStartOf68Header(buffer, beginReader)) { - break; + break; // 读到了协议的开始标志,结束while循环 } // 未读到包头,略过一个字节 @@ -138,6 +142,7 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder { buffer.resetReaderIndex(); } + // 判断是否为DNY包头 private boolean isStartOfDnyHeader(ByteBuf buffer, int beginReader) { if (buffer.readableBytes() >= HEADER_LENGTH_DNY) { byte[] headerBytes = new byte[HEADER_LENGTH_DNY]; @@ -148,6 +153,7 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder { return false; } + // 判断是否为68包头 private boolean isStartOf68Header(ByteBuf buffer, int beginReader) { if (buffer.readableBytes() >= HEADER_LENGTH_68) { return buffer.getUnsignedByte(beginReader) == 0x68; @@ -155,14 +161,17 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder { return false; } + // 处理68协议消息 private void decode68Message(ByteBuf buffer, List out, int beginReader) { + // 检查剩余数据是否足够 if (buffer.readableBytes() < HEADER_LENGTH_68 + 1) { buffer.readerIndex(beginReader); return; } - // 消息的长度 + // 获取消息长度 int length = buffer.getUnsignedByte(beginReader + HEADER_LENGTH_68); + // 检查剩余数据是否足够 if (buffer.readableBytes() < HEADER_LENGTH_68 + 1 + length) { buffer.readerIndex(beginReader); return; @@ -174,14 +183,17 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder { 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); + // 检查剩余数据是否足够 if (buffer.readableBytes() < HEADER_LENGTH_DNY + 1 + length) { buffer.readerIndex(beginReader); return; diff --git a/jsowell-netty/src/main/java/com/jsowell/netty/domain/ProtocolDnyMessage.java b/jsowell-netty/src/main/java/com/jsowell/netty/domain/ProtocolDnyMessage.java new file mode 100644 index 000000000..76ee060df --- /dev/null +++ b/jsowell-netty/src/main/java/com/jsowell/netty/domain/ProtocolDnyMessage.java @@ -0,0 +1,49 @@ +package com.jsowell.netty.domain; + +public class ProtocolDnyMessage { + private final byte[] header; + private final int length; + private final byte[] physicalId; + private final int messageId; + private final byte command; + private final byte[] data; + private final int checksum; + + public ProtocolDnyMessage(byte[] header, int length, byte[] physicalId, int messageId, byte command, byte[] data, int checksum) { + this.header = header; + this.length = length; + this.physicalId = physicalId; + this.messageId = messageId; + this.command = command; + this.data = data; + this.checksum = checksum; + } + + public byte[] getHeader() { + return header; + } + + public int getLength() { + return length; + } + + public byte[] getPhysicalId() { + return physicalId; + } + + public int getMessageId() { + return messageId; + } + + public byte getCommand() { + return command; + } + + public byte[] getData() { + return data; + } + + public int getChecksum() { + return checksum; + } +} \ No newline at end of file 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 51208a5b0..935646b4a 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,5 +1,6 @@ package com.jsowell.netty.server.electricbicycles; +import com.jsowell.netty.decoder.ProtocolDnyDecoder; import com.jsowell.netty.decoder.StartAndLengthFieldFrameDecoder; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; @@ -21,7 +22,7 @@ public class ElectricBicyclesServerChannelInitializer extends ChannelInitializer protected void initChannel(SocketChannel channel) throws Exception { ChannelPipeline pipeline = channel.pipeline(); // pipeline.addLast("frameDecoder",new CustomDecoder()); - pipeline.addLast("frameDecoder", new StartAndLengthFieldFrameDecoder()); + pipeline.addLast("frameDecoder", new ProtocolDnyDecoder()); pipeline.addLast("decoder", new ByteArrayDecoder()); pipeline.addLast("encoder", new ByteArrayDecoder()); //读超时时间设置为10s,0表示不监控