update 重构

This commit is contained in:
Guoqs
2024-11-26 16:30:30 +08:00
parent 698da5d8c7
commit b34ed6c217
3 changed files with 129 additions and 2 deletions

View File

@@ -0,0 +1,96 @@
package com.jsowell.netty.decoder;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.DecoderException;
public class CustomLengthFieldBasedFrameDecoder extends LengthFieldBasedFrameDecoder {
private static final int MAX_FRAME_LENGTH = 256; // 最大帧长度
private static final int LENGTH_FIELD_OFFSET = 1; // 数据长度字段的偏移位置
private static final int LENGTH_FIELD_LENGTH = 1; // 数据长度字段占的字节数
public CustomLengthFieldBasedFrameDecoder() {
super(MAX_FRAME_LENGTH, LENGTH_FIELD_OFFSET, LENGTH_FIELD_LENGTH, 0, 0);
}
@Override
protected Object decode(io.netty.channel.ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
if (buffer.readableBytes() < 5) {
return null; // 至少要有起始标志1字节 + 数据长度1字节 + 序列号域2字节
}
// 校验起始标志是否为0x68
byte startFlag = buffer.getByte(buffer.readerIndex());
if (startFlag != (byte) 0x68) {
throw new DecoderException("Invalid start flag, expected 0x68 but got 0x" + Integer.toHexString(startFlag));
}
// 计算数据长度
buffer.skipBytes(1); // 跳过起始标志
byte dataLength = buffer.readByte(); // 读取数据长度字段
// 如果数据长度大于实际可读取的字节数,返回 null 等待更多数据
if (buffer.readableBytes() < dataLength) {
return null;
}
// 读取序列号域、加密标志、帧类型标志、消息体和帧校验域
short serialNumber = buffer.readShort(); // 读取序列号域2字节
byte encryptFlag = buffer.readByte(); // 读取加密标志1字节
byte frameTypeFlag = buffer.readByte(); // 读取帧类型标志1字节
ByteBuf messageBody = buffer.readBytes(dataLength - 6); // 读取消息体数据(数据长度 - 6字节
// 读取并校验帧校验域CRC
short expectedCrc = buffer.readShort(); // 读取校验域2字节
// 校验 CRC
short actualCrc = calculateCrc(serialNumber, encryptFlag, frameTypeFlag, messageBody);
if (actualCrc != expectedCrc) {
throw new DecoderException("CRC mismatch, expected: " + Integer.toHexString(expectedCrc) + ", but got: " + Integer.toHexString(actualCrc));
}
// 构造并返回完整的数据包对象
return new CustomMessage(serialNumber, encryptFlag, frameTypeFlag, messageBody);
}
// CRC 校验计算方法
private short calculateCrc(short serialNumber, byte encryptFlag, byte frameTypeFlag, ByteBuf messageBody) {
// CRC 计算可以使用指定的 CRC 多项式 0x180D 进行计算
// 这里可以实现 CRC 校验的具体计算逻辑,返回计算得到的 CRC 值
// 简单示范,这里返回一个默认值,实际应根据具体协议计算
return (short) 0xFFFF; // 这里只是一个示例值,实际要根据数据进行计算
}
// 自定义消息类,包含协议解析后的字段
public static class CustomMessage {
private short serialNumber;
private byte encryptFlag;
private byte frameTypeFlag;
private ByteBuf messageBody;
public CustomMessage(short serialNumber, byte encryptFlag, byte frameTypeFlag, ByteBuf messageBody) {
this.serialNumber = serialNumber;
this.encryptFlag = encryptFlag;
this.frameTypeFlag = frameTypeFlag;
this.messageBody = messageBody;
}
// Getter 方法
public short getSerialNumber() {
return serialNumber;
}
public byte getEncryptFlag() {
return encryptFlag;
}
public byte getFrameTypeFlag() {
return frameTypeFlag;
}
public ByteBuf getMessageBody() {
return messageBody;
}
}
}

View File

@@ -0,0 +1,30 @@
package com.jsowell.netty.decoder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;
/**
* 自定义LengthFieldBasedFrameDecoder
*/
@Slf4j
public class MyLengthFieldBasedFrameDecoder extends LengthFieldBasedFrameDecoder {
/*
构造方法
maxFrameLength指定解码器所能处理的数据包的最大长度超过该长度则抛出 TooLongFrameException 异常;
lengthFieldOffset指定长度字段的起始位置
lengthFieldLength指定长度字段的长度目前支持1(byte)、2(short)、3(3个byte)、4(int)、8(Long)
lengthAdjustment指定长度字段所表示的消息长度值与实际长度值之间的差值可以用于调整解码器的计算和提高灵活性。
initialBytesToStrip指定解码器在将数据包分离出来后跳过的字节数因为这些字节通常不属于消息体内容而是协议头或其他控制信息。
lengthAdjustment可正可负需要满足以下的计算关系
*/
public MyLengthFieldBasedFrameDecoder() {
super(208, 1, 1, 0, 2);
}
@Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
return super.decode(ctx, in);
}
}

View File

@@ -1,6 +1,6 @@
package com.jsowell.netty.server.yunkuaichong; package com.jsowell.netty.server.yunkuaichong;
import com.jsowell.netty.decoder.StartAndLengthFieldFrameDecoder; import com.jsowell.netty.decoder.CustomLengthFieldBasedFrameDecoder;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
@@ -21,7 +21,8 @@ public class NettyServerChannelInitializer extends ChannelInitializer<SocketChan
protected void initChannel(SocketChannel channel) throws Exception { protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline(); ChannelPipeline pipeline = channel.pipeline();
// pipeline.addLast("frameDecoder",new CustomDecoder()); // pipeline.addLast("frameDecoder",new CustomDecoder());
pipeline.addLast("frameDecoder", new StartAndLengthFieldFrameDecoder()); // pipeline.addLast("frameDecoder", new StartAndLengthFieldFrameDecoder());
pipeline.addLast("frameDecoder", new CustomLengthFieldBasedFrameDecoder());
pipeline.addLast("decoder", new ByteArrayDecoder()); pipeline.addLast("decoder", new ByteArrayDecoder());
pipeline.addLast("encoder", new ByteArrayDecoder()); pipeline.addLast("encoder", new ByteArrayDecoder());
//读超时时间设置为10s0表示不监控 //读超时时间设置为10s0表示不监控