Java Netty解码器在写入字符串时抛出IndexOutOfBounsException

Java Netty解码器在写入字符串时抛出IndexOutOfBounsException,java,netty,Java,Netty,堆垛机。我目前正在使用netty编写一些网络内容,其模式如下: 簇 客户1 客户2 客户3 当我启动客户机时,它连接到一个集群,集群将我的对象(称为ServerDataPacket)发送到所有连接的客户机。所有客户端都成功接收ServerDataPacket对象。 但是,当我在一个客户机中执行某些操作时,问题就开始了。例如,我在客户机1中做了一些事情,它向集群发送另一个对象,集群再次接收并向所有客户机发送对象服务器数据包。所有客户端都会收到此对象,但不是客户端1,客户端1会抛出此错误,

堆垛机。我目前正在使用netty编写一些网络内容,其模式如下:

    • 客户1
    • 客户2
    • 客户3
当我启动客户机时,它连接到一个集群,集群将我的对象(称为ServerDataPacket)发送到所有连接的客户机。所有客户端都成功接收ServerDataPacket对象。 但是,当我在一个客户机中执行某些操作时,问题就开始了。例如,我在客户机1中做了一些事情,它向集群发送另一个对象,集群再次接收并向所有客户机发送对象服务器数据包。所有客户端都会收到此对象,但不是客户端1,客户端1会抛出此错误,而不是完整信息:

io.netty.handler.codec.DecoderException: java.lang.IndexOutOfBoundsException: index: 501, length: 15 (expected: range(0, 512))
        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:373)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:351)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:651)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:574)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:488)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:450)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873)
        at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IndexOutOfBoundsException: index: 501, length: 15 (expected: range(0, 512))
        at io.netty.buffer.AbstractByteBuf.checkIndex0(AbstractByteBuf.java:1359)
        at io.netty.buffer.AbstractByteBuf.checkIndex(AbstractByteBuf.java:1354)
        at io.netty.buffer.PooledUnsafeDirectByteBuf.internalNioBuffer(PooledUnsafeDirectByteBuf.java:331)
        at io.netty.buffer.ByteBufUtil.decodeString(ByteBufUtil.java:614)
        at io.netty.buffer.AbstractByteBuf.toString(AbstractByteBuf.java:1213)
        at io.netty.buffer.AbstractByteBuf.getCharSequence(AbstractByteBuf.java:492)
        at io.netty.buffer.AbstractByteBuf.readCharSequence(AbstractByteBuf.java:497)
        at net.novaplay.common.network.bungee.ServerDataPacket.read(ServerDataPacket.java:45)
        at net.novaplay.common.netty.packet.PacketDecoder.decode(PacketDecoder.java:29)
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411)
        ... 16 more
对bytebuffer中的字符串进行解码会导致错误

    @Override
    public void read(ByteBuf buf){
            int length = buf.readInt();
            String id = (String)buf.readCharSequence(length, Charsets.UTF_8); //here i got an error
    }
我的netty解码器:

public class PacketDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> output) throws Exception {
        while(byteBuf.readableBytes() > 0) {
            int id = byteBuf.readInt();
            if(NettyHandler.DEBUG) {
                System.out.println("Packet ID: " + id);
            }
            Class<? extends Packet> packetClass = PacketHandler.PACKETS.get(id);
            if(packetClass == null) {
                throw new NullPointerException("Couldn't find packet by id " + id);
            }
            Packet packet = packetClass.newInstance();
            int length = byteBuf.readInt();
            packet.uniqueId = UUID.fromString( (String) byteBuf.readCharSequence(length, Charsets.UTF_8)); //memory leak here, view UPD.2
            packet.read(byteBuf); //memory leak here, view UPD.2
            output.add(packet);
            if(NettyHandler.DEBUG) {
                System.out.println("Packet successfully has been decoded");
            }
        }
    }
}
公共类PacketDecoder扩展为tetomessagedecoder{
@凌驾
受保护的无效解码(ChannelHandlerContext ctx、ByteBuf ByteBuf、列表输出)引发异常{
while(byteBuf.readableBytes()>0){
int id=byteBuf.readInt();
if(NettyHandler.DEBUG){
System.out.println(“数据包ID:+ID”);
}

Class这里的问题是由数据如何通过网络发送引起的。不能保证由
ByteToMessageDecoder
接收的数据完全由完整的数据包组成-您可能只接收一个数据包的一部分,或者多个完整的数据包后接一个不完整的数据包。有两种简单的方法可以解决此问题:

  • 在解码器中添加一个检查(作为
    while
    循环主体中的第一件事),以确保缓冲区包含完整的数据包,如果没有足够的可读字节,则退出而不修改缓冲区的
    readerIndex
  • 在数据包解码器之前向管道中添加一个。这将自动读取并丢弃长度前缀,并为每个长度前缀部分向解码器传递一个缓冲区。请注意,这将要求您在数据包的开头添加另一个长度前缀,包含整个数据包的长度(带有ID、UUID以及实际的数据包主体)
额外好处:您对字符串的编码方法不正确。
ByteBuf#writeCharSequence
返回写入的字节数,
ByteBuf#readCharSequence
要求字符串的大小以字节为单位,而不是以字符为单位。它适合您的用例,因为UUID的文本表示形式只包含单字节字符,而不是以字符为单位一般来说,您应该使用以下内容:

int lengthPrefixIndex = buffer.writerIndex();
int length = buffer.writeInt(-1).writeCharSequence(text, StandardCharsets.UTF_8);
buffer.setInt(lengthPrefixIndex, length);
另外,
ByteBuf#readCharSequence
不能保证返回
字符串
,您应该删除强制转换,并用调用
toString()
替换它

io.netty.handler.codec.DecoderException: java.lang.IndexOutOfBoundsException: readerIndex(512) + length(4) exceeds writerIndex(512): PooledUnsafeDirectByteBuf(ridx: 512, widx: 512, cap: 512)
        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:373)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:351)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:651)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:574)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:488)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:450)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873)
        at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IndexOutOfBoundsException: readerIndex(512) + length(4) exceeds writerIndex(512): PooledUnsafeDirectByteBuf(ridx: 512, widx: 512, cap: 512)
        at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1395)
        at io.netty.buffer.AbstractByteBuf.readInt(AbstractByteBuf.java:766)
        at net.novaplay.common.network.bungee.ServerDataPacket.read(ServerDataPacket.java:45)
        at net.novaplay.common.netty.packet.PacketDecoder.decode(PacketDecoder.java:29)
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411)
        ... 16 more
Packet ID: 9
Got io.netty.handler.codec.DecoderException: java.lang.OutOfMemoryError: Java heap space at
io.netty.handler.codec.DecoderException: java.lang.OutOfMemoryError: Java heap space
        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:373)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:351)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:651)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:574)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:488)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:450)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873)
        at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.OutOfMemoryError: Java heap space
        at java.nio.HeapCharBuffer.<init>(HeapCharBuffer.java:57)
        at java.nio.CharBuffer.allocate(CharBuffer.java:335)
        at io.netty.buffer.ByteBufUtil.decodeString(ByteBufUtil.java:605)
        at io.netty.buffer.AbstractByteBuf.toString(AbstractByteBuf.java:1213)
        at io.netty.buffer.AbstractByteBuf.getCharSequence(AbstractByteBuf.java:492)
        at io.netty.buffer.AbstractByteBuf.readCharSequence(AbstractByteBuf.java:497)
        at net.novaplay.common.netty.packet.PacketDecoder.decode(PacketDecoder.java:28)
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411)
        ... 16 more
int lengthPrefixIndex = buffer.writerIndex();
int length = buffer.writeInt(-1).writeCharSequence(text, StandardCharsets.UTF_8);
buffer.setInt(lengthPrefixIndex, length);