Netty 包和设置 Frames

Netty packets and setting Frames

目前我正在开发一个PacketSystem。通过它我制作了一个身份验证系统并创建了一个密钥,该密钥作为字符串从客户端发送到服务器,如下所示:

protected void channelRead0(ChannelHandlerContext ctx, Packet p) throws Exception {
    if(p instanceof PacketInServerAuthRequest) {
        System.out.println("Sending WrapperAuthKey. Waiting for answer...");
        send(new PacketOutServerAuthAnswer(NetworkUtils.readWrapperKey()));
    }
}

服务器不知何故收到了三次WrapperKey。最后两次没有数据包 ID 并导致这两个异常:

SEVERE: Nov 19, 2017 9:56:35 PM io.netty.channel.DefaultChannelPipeline onUnhandledInboundException
WARNUNG: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.handler.codec.DecoderException: java.lang.IndexOutOfBoundsException: readerIndex(8) + length(4) exceeds writerIndex(9): PooledUnsafeDirectByteBuf(ridx: 8, widx: 9, cap: 1024)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:442)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:624)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:559)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:476)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438)
    at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:858)
    at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IndexOutOfBoundsException: readerIndex(8) + length(4) exceeds writerIndex(9): PooledUnsafeDirectByteBuf(ridx: 8, widx: 9, cap: 1024)
    at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1396)
    at io.netty.buffer.AbstractByteBuf.readInt(AbstractByteBuf.java:766)
    at me.micha.flickcloud.netty.handler.PacketDecoder.decode(PacketDecoder.java:13)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411)
    ... 16 more

SEVERE: Nov 19, 2017 9:56:35 PM io.netty.channel.DefaultChannelPipeline onUnhandledInboundException
WARNUNG: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.handler.codec.DecoderException: java.lang.IndexOutOfBoundsException: readerIndex(16) + length(4) exceeds writerIndex(17): PooledUnsafeDirectByteBuf(ridx: 16, widx: 17, cap: 1024)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:442)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:624)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:559)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:476)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438)
    at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:858)
    at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IndexOutOfBoundsException: readerIndex(16) + length(4) exceeds writerIndex(17): PooledUnsafeDirectByteBuf(ridx: 16, widx: 17, cap: 1024)
    at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1396)
    at io.netty.buffer.AbstractByteBuf.readInt(AbstractByteBuf.java:766)
    at me.micha.flickcloud.netty.handler.PacketDecoder.decode(PacketDecoder.java:13)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411)
    ... 16 more

经过一些研究,我发现我可能必须使用 LengthFieldPrepender 和 LengthFieldBasedFrameDecoder 来告诉服务器字符串何时结束,但我真的不知道如何使用它们。也许我通常在通过 ByteBuf 发送字符串时犯了一个错误。

如果有人能解决我的问题,我将不胜感激。

编辑: 这就是我在两侧(服务器和客户端)初始化频道的方式:

public static Channel initChannel(Channel channel) {
    channel.pipeline()
    .addLast(new PacketDecoder())
    .addLast(new PacketEncoder());

    return channel;
}

请记住,netty 是一个异步/非阻塞框架,这意味着从 Channel 读取的数据可以分段(就像一般的 TCP)。在 ByteToMessageDecoder 实施中尝试之前,您需要确保有足够的数据可供读取。好像您尝试读取 Int 并且没有剩余 4 个字节可供读取。