Netty 4.01 CR6 的偶发性 OutOfBounds 问题
Sparodic OutOfBounds issue with Netty 4.01 CR6
我开发的自定义解码器有问题,我不确定自己做错了什么。
我们收到的消息格式包含HEADER、BODY和TRAILER。 header 是 1 个字节,是一个 STX (0x02) body 是可变长度 尾部是 2 个字节,包含一个 ETX(0x03),后跟一个 LRC。
所以典型的消息可能如下所示:
STX BODY ETX LRC
02 37000000 06 18
解码器的输出应该是没有STX控制字节的消息。所以发送的消息是:
BODY ETX LRC
37000000 06 18
我们扩展了 DelimiterBasedFrameDecoder 并将 ETX 定义为分隔符。解码器的目的是读取下一个字节,将其添加到缓冲区然后继续发送,这样我们就可以发送完整的消息。我们的解码方法如下所示:
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
Object frame = super.decode(ctx, buffer);
if (frame == null) {
return null;
}
ByteBuf msg = null;
if (frame instanceof ByteBuf) {
msg = Unpooled.copiedBuffer((ByteBuf) frame);
msg.writeByte(buffer.readByte());
((ByteBuf) frame).release();
}
while (msg.getByte(0) != STX) {
msg.readByte();
msg = msg.discardReadBytes();
}
return msg;
}
一切都按预期工作,除了我们会定期收到以下异常。
java.lang.IndexOutOfBoundsException: readerIndex(225) + length(1) exceeds writerIndex(225): UnpooledUnsafeDirectByteBuf(ridx: 225, widx: 225, cap: 256)
我们正在使用 Netty 4.01 CR6,这是一个偶发问题。我不确定的是,这是我做的不正确,还是 Netty 内部的问题。由于我是 Netty 的新手,我怀疑这是我正在做的事情,但我不确定。
我希望有人能帮我解决这个问题。我很乐意 post 更多信息来解决这个问题,请问。
感谢我能在这方面得到的所有帮助。
- 蒂姆
此异常意味着您正试图从 bytebuf 中读取一个它不包含的字节,因为您已到达它的末尾。
客户端发送了无效数据,或者您的协议中并非所有数据包都在消息中包含 STX
。
解码现有协议时常犯的另一个错误是,您用作定界符的字节序列在数据包本身内部使用,并且您应该逐字节读取数据包。
如果你想看到数据包流向你的解码器,你可以添加一个 LoggingHandler(LogLevel.INFO)
到管道,就在你的解码器 运行 之前,所以它会打印出原始字节作为十六进制,因此您可以检查它是否确实包含所需的字节序列。
旁注:你永远不会释放存储在msg
中的bytebuf。这将造成内存泄漏并最终导致 OOM,确保在 try-finally 块中调用 release,因此它总是被调用
我开发的自定义解码器有问题,我不确定自己做错了什么。
我们收到的消息格式包含HEADER、BODY和TRAILER。 header 是 1 个字节,是一个 STX (0x02) body 是可变长度 尾部是 2 个字节,包含一个 ETX(0x03),后跟一个 LRC。
所以典型的消息可能如下所示:
STX BODY ETX LRC
02 37000000 06 18
解码器的输出应该是没有STX控制字节的消息。所以发送的消息是:
BODY ETX LRC
37000000 06 18
我们扩展了 DelimiterBasedFrameDecoder 并将 ETX 定义为分隔符。解码器的目的是读取下一个字节,将其添加到缓冲区然后继续发送,这样我们就可以发送完整的消息。我们的解码方法如下所示:
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
Object frame = super.decode(ctx, buffer);
if (frame == null) {
return null;
}
ByteBuf msg = null;
if (frame instanceof ByteBuf) {
msg = Unpooled.copiedBuffer((ByteBuf) frame);
msg.writeByte(buffer.readByte());
((ByteBuf) frame).release();
}
while (msg.getByte(0) != STX) {
msg.readByte();
msg = msg.discardReadBytes();
}
return msg;
}
一切都按预期工作,除了我们会定期收到以下异常。
java.lang.IndexOutOfBoundsException: readerIndex(225) + length(1) exceeds writerIndex(225): UnpooledUnsafeDirectByteBuf(ridx: 225, widx: 225, cap: 256)
我们正在使用 Netty 4.01 CR6,这是一个偶发问题。我不确定的是,这是我做的不正确,还是 Netty 内部的问题。由于我是 Netty 的新手,我怀疑这是我正在做的事情,但我不确定。
我希望有人能帮我解决这个问题。我很乐意 post 更多信息来解决这个问题,请问。
感谢我能在这方面得到的所有帮助。
- 蒂姆
此异常意味着您正试图从 bytebuf 中读取一个它不包含的字节,因为您已到达它的末尾。
客户端发送了无效数据,或者您的协议中并非所有数据包都在消息中包含 STX
。
解码现有协议时常犯的另一个错误是,您用作定界符的字节序列在数据包本身内部使用,并且您应该逐字节读取数据包。
如果你想看到数据包流向你的解码器,你可以添加一个 LoggingHandler(LogLevel.INFO)
到管道,就在你的解码器 运行 之前,所以它会打印出原始字节作为十六进制,因此您可以检查它是否确实包含所需的字节序列。
旁注:你永远不会释放存储在msg
中的bytebuf。这将造成内存泄漏并最终导致 OOM,确保在 try-finally 块中调用 release,因此它总是被调用