decode()除了解码消息外没有读取任何内容

时间:2015-03-18 18:01:42

标签: java sockets netty

对于套接字服务器应用程序,我创建了一个PacketFragmenter,它读取数据包的长度(在数据包的第二个字节中),然后将数据包发送回管道。

这是我写的代码:

public class PacketFragmenter extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in,
            List<Object> out) throws Exception {
        //I read a byte just to make the reader index go to second byte
        in.readByte();

        //in the second byte i get the content's length
        int length = in.readByte();

        //if my content is smaller than the readableBytes, there's a problem, so i return
        if (in.readableBytes() < length) {
            return;
        }

        //If everything is good, i reset the reader index to be able to write the whole packet in the out buffer (because i need the first byte in next handler, same for the size)
        in.resetReaderIndex();
        //I send my packet to the next handler
        out.add(in.readBytes(length +2));
        //and i reset the rederIndex to be able to read another packet
        in.resetReaderIndex();
    }

}

我在测试中得到了这个堆栈:

io.netty.handler.codec.DecoderException: PacketFragmenter.decode() did not read anything but decoded a message.
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:334)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:229)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:339)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:324)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:847)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:111)
    at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
    at java.lang.Thread.run(Thread.java:745)

但是一切都在播放,我连续收到两个数据包,但它们拼接得很好,下一个处理程序正在完成他的工作。

所以我不知道我是应该处理这个异常还是忽略它?或者也许我可以做一件简单的事来解决它,我根本不是一个网络专家(一周前开始),所以应该很容易修复。但我在netty的用户指南中找不到任何内容。

2 个答案:

答案 0 :(得分:2)

我会向Supamiu的答案添加更多信息。 在许多情况下,使用LengthFieldBasedFrameDecoder作为父类是正确的方法,但没有解释为什么会引发异常。

如果您生成消息,则还需要阅读ByteBuf中的内容。添加此检查以捕获由用户解码器错误生成的无限循环。

因此,如果您从原始方法中删除最后一行in.resetReaderIndex();,则异常将消失:

public class PacketFragmenter extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        in.skipBytes(1);
        //in the second byte i get the content's length
        int length = in.readByte();

        //if my content is smaller than the readableBytes, there's a problem, so i return
        if (in.readableBytes() < length) {
            return;
        }

        //If everything is good, i reset the reader index to be able to write the whole packet in the out buffer (because i need the first byte in next handler, same for the size)
        in.resetReaderIndex();
        //I send my packet to the next handler
        out.add(in.readBytes(length + 2));
    }
}

答案 1 :(得分:0)

public class PacketFrameDecoder extends LengthFieldBasedFrameDecoder {

    private static final int MAX_PACKET_LENGTH = 8192 * 2;
    private static final int LENGTH_FIELD_OFFSET = 1;
    private static final int LENGTH_FIELD_LENGTH = 1;
    private static final int LENGTH_FIELD_ADJUSTMENT = 0;
    private static final int INITIAL_BYTES_TO_STRIP = 0;

    public PacketFrameDecoder()
    {
        super(MAX_PACKET_LENGTH, LENGTH_FIELD_OFFSET, LENGTH_FIELD_LENGTH, LENGTH_FIELD_ADJUSTMENT, INITIAL_BYTES_TO_STRIP);
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception 
    {
        return super.decode(ctx, in);
    }
}

以下是我如何修复它,实际上有一个为此完成的LengthFieldBasedFrameDecoder,无需扩展ByteToMessageDecoder。