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位结果 } }