定长解码器
FixedLengthFrameDecoder 的工作原理
FixedLengthFrameDecoder 通过构造函数设置期望的消息长度 frameLength。解码器将按照以下步骤工作:
使用 FixedLengthFrameDecoder 的示例
假设我们有一个简单的二进制协议,每个消息恰好为10个字节。我们可以如下方式使用 FixedLengthFrameDecoder:
public class CustomFixedLengthFrameDecoder extends FixedLengthFrameDecoder {
public CustomFixedLengthFrameDecoder() {
super(10); // 设置固定长度为10
}
@Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
// 调用 super.decode() 将自动处理固定长度的拆包
ByteBuf buf = (ByteBuf) super.decode(ctx, in);
if (buf != null) {
// 在这里可以添加额外的处理逻辑,如果需要的话
return buf; // 将 ByteBuf 作为消息传递给下一个处理程序
}
return null;
}
}
在实际应用中,我们可能需要对解码后的消息进行进一步的处理。例如,我们可以将解码后的消息转换成一个 CustomMessage 对象,而不是直接传递 ByteBuf:
public class CustomMessageDecoder extends ByteToMessageDecoder {
private static final int FRAME_LENGTH = 10;
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
// 检查是否有足够的数据
if (in.readableBytes() < FRAME_LENGTH) {
return;
}
// 读取固定长度的数据
ByteBuf buf = in.readBytes(FRAME_LENGTH);
// 将 ByteBuf 转换为自定义消息对象
CustomMessage message = new CustomMessage(buf.readInt(), buf.readLong());
out.add(message);
}
}
// CustomMessage 类定义
public class CustomMessage {
private int field1;
private long field2;
public CustomMessage(int field1, long field2) {
this.field1 = field1;
this.field2 = field2;
}
// 省略 getter 和 setter 方法
}
分隔符解码器
DelimiterBasedFrameDecoder 是 Netty 提供的另一种强大的解码器,它允许开发者基于特殊分隔符来拆分消息。这种解码器特别适用于文本协议,其中消息通常以换行符、逗号或其他特殊字符分隔。以下是对 DelimiterBasedFrameDecoder 的几个关键属性的详细介绍,以及如何使用这个解码器的示例。
关键属性
-
delimiters:
-
maxLength:
-
failFast:
-
stripDelimiter:
示例
假设我们有一个基于换行符 \n 和回车换行 \r\n 结尾的文本协议,我们可以这样使用 DelimiterBasedFrameDecoder:
public class CustomDelimiterFrameDecoder extends DelimiterBasedFrameDecoder {
public CustomDelimiterFrameDecoder() {
// 指定多个分隔符,这里使用换行符 '\n' 和回车换行 '\r\n'
super(100, true, Unpooled.copiedBuffer("\n\r\n", CharsetUtil.UTF_8));
}
@Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf buf = (ByteBuf) super.decode(ctx, in);
if (buf == null) {
return null;
}
// 根据需要,这里可以添加额外的处理逻辑
// 返回解码后的消息,这里我们假设它是一个字符串
return buf.toString(CharsetUtil.UTF_8);
}
}
长度域解码器
长度域解码器特有属性
-
lengthFieldOffset:
-
lengthFieldLength:
-
lengthAdjustment:
-
initialBytesToStrip:
-
lengthFieldEndOffset:
与其他解码器相似的属性
-
maxFrameLength:
-
failFast:
-
discardingTooLongFrame:
-
tooLongFrameLength:
-
bytesToDiscard:
示例
假设我们设计了一个简单的二进制协议,其中每个消息的开始是一个4字节的长度字段,后面跟着实际的数据。我们可以这样使用 LengthFieldBasedFrameDecoder:
public class CustomLengthFieldBasedFrameDecoder extends LengthFieldBasedFrameDecoder {
public CustomLengthFieldBasedFrameDecoder() {
// 长度字段偏移量为0,长度为4字节,不包含任何额外的头部信息,长度无需修正
super(1024 * 1024, 0, 4, 0, 4);
}
@Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf buf = (ByteBuf) super.decode(ctx, in);
if (buf == null) {
return null;
}
// 在这里可以添加额外的处理逻辑,如果需要的话
return buf;
}
}