Netty:奇怪的 IndexOutOfBoundsException:readerIndex + 长度超过 writerIndex

2024-05-03

我目前正在通过 netty 发送不同的数据包,并且经常遇到这样的异常收到它们时:

java.lang.IndexOutOfBoundsException: readerIndex(39) + length(32) exceeds writerIndex(64): UnpooledUnsafeDirectByteBuf(ridx: 39, widx: 64, cap: 2048)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1166)
at io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:655) 
at <snip>.PacketDataHolder.readString(PacketDataHolder.java:79)

...... 或者

java.lang.IndexOutOfBoundsException: readerIndex(0) + length(1) exceeds writerIndex(0): UnpooledUnsafeDirectByteBuf(ridx: 0, widx: 0, cap: 2048)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1166)
at io.netty.buffer.AbstractByteBuf.readByte(AbstractByteBuf.java:570) ......

这是我发送数据包的方式:

public void sendPacket(Packet packet) {
    PacketDataHolder packetDataHolder = new PacketDataHolder(); //I'm creating a packetDataHolder, code is below
    packetDataHolder.writeHeader(packet); //Then i'm adding the packet ID as a header
    packet.writeData(packetDataHolder); //Then I'm writing the data of the packet (String for example)
    socketChannel.writeAndFlush(packetDataHolder.getByteBuf()); //Then I'm sending the packet
}

以及我如何接收和阅读它们:

protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
    PacketDataHolder packetDataHolder = new PacketDataHolder(byteBuf); //First I'm creating a PacketDataHolder containing the bytebuf
    Packet packet = PacketParser.parsePacket(packetDataHolder); //Then I'm parsing the header I wrote (The packet id)

这是相关代码:

(PacketDataHolder 类) 公共同步无效writeHeader(数据包数据包){ this.writeByte(packet.getId()); }

public synchronized byte readHeader() {
    return this.readByte();
}
public synchronized void writeByte(int value) {
    this.byteBuf.writeByte(value);
}

public synchronized byte readByte() {
    return this.byteBuf.readByte();
}
public synchronized void writeString(String value) {
    if(value == null)
        value = "An error occurred while displaying this message";
    byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
    if (bytes.length > 32767)
        throw new EncoderException("String too big (was " + value.length()
                + " bytes encoded, max 32767)");
    else {
        writeVarInt(bytes.length);
        byteBuf.writeBytes(bytes);
    }
}

public synchronized String readString() {
    int length = readVarInt();
    if (length < 0)
        throw new DecoderException(
                "The received encoded string buffer length is less than zero! Weird string!");
    return new String(byteBuf.readBytes(length).array(),
            StandardCharsets.UTF_8);
}

我描述的第一个错误总是发生在 writeString 方法中,所以我认为它以任何方式与此相关。 我认为这主要是在发送很长的字符串时发生的,但我不确定。

如果您需要更多示例代码,请随时询问! 我希望你可以帮助我, 燃烧器


您的代码假设您的通信通道正在处理帧。也就是说,它期望当您发送 1024 字节时,接收处理程序将收到正好 1024 字节的 bytebuf。据我所知,您的代码直接写入 TCP,这是一种基于流的协议,不能以这种方式工作。如果写入 1024 字节,对等方将收到所有 1024 字节,但字节可能会分段到达 - 例如两次调用channelRead0(第一个调用 300,第二个调用 724)。

幸运的是,Netty 包含几个开箱即用的帧编解码器来为您处理这个问题。请参阅以下位置的示例http://netty.io/4.0/xref/io/netty/example/worldclock/WorldClockServerInitializer.html http://netty.io/4.0/xref/io/netty/example/worldclock/WorldClockServerInitializer.html

它展示了如何使用 ProtobufVarint32FrameDecoder(确保管道中的下一个处理程序一次始终接收一帧字节)和 ProtobufVarint32LengthFieldPrepender(负责将帧长度标头添加到所有传出消息中)配置服务器通道

我建议您更改代码以将这些(或类似的帧编解码器)插入到您的管道中。然后将您的应用程序代码修改为not调用 readVarInt 和 writeVarInt 因为编解码器会为您处理这个问题。接收到的 ByteBuf 的大小将始终与发送的 ByteBuf 的大小匹配,因为解码器负责聚合所有片段。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Netty:奇怪的 IndexOutOfBoundsException:readerIndex + 长度超过 writerIndex 的相关文章