我开发的自定义解码器有问题,不确定我做错了什么。
我们收到的消息格式包含HEADER、BODY和TRAILER。标头为1个字节,为STX(0x02)正文为可变长度。尾部为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的新手,我怀疑这是我正在做的事情,但我不确定。
我希望有人能帮我解决这个问题。我更乐意发布更多信息来解决这个问题,只需询问即可。
感谢我在这件事上所能得到的一切帮助。
- 蒂姆
这个异常意味着你正试图从它不包含的字节中读取一个字节,因为你已经到达了它的末尾。
客户端发送了无效数据,或者您的协议中并非所有数据包的消息中都包含STX
。
解码现有协议时通常会犯的另一个错误是,您用作分隔符的字节序列被用于数据包本身,并且您需要逐字节读取数据包。
如果你想看到数据包流向解码器,你可以在解码器运行之前向管道添加一个LoggingHandler(LogLevel.INFO)
,这样它就会将原始字节打印为十六进制,这样你就可以检查它是否真的包含所需的字节序列。
旁注:您永远不会释放存储在msg
中的字节。这将导致内存泄漏,并最终导致OOM,请确保在try-filly块中调用release,使其始终被称为