java.lang.IndexOutOfBoundsException 在数据包系统中使用 Netty 的异常
java.lang.IndexOutOfBoundsException Exception using Netty in a packet system
我目前正在编写一个通过数据包进行通信的系统。这也有效。我有一台服务器和理论上无限的客户端。当我只启动一个客户端时,它工作得很好,但是当我启动多个客户端时,我总是在程序运行 2-3 分钟后出现 java.lang.IndexOutOfBoundsException
异常。
异常
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(77) + length(36) exceeds writerIndex(112): PooledUnsafeDirectByteBuf(ridx: 77, widx: 112, cap: 112)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:478)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:795)
at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:480)
at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:378)
at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IndexOutOfBoundsException: readerIndex(77) + length(36) exceeds writerIndex(112): PooledUnsafeDirectByteBuf(ridx: 77, widx: 112, cap: 112)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1442)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1428)
at io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:895)
at io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:903)
at eu.diamondcloudservice.wrapper.packets.incoming.PacketInCloudServerConnect.read(PacketInCloudServerConnect.java:79)
at eu.diamondcloudservice.wrapper.network.PacketDecoder.decode(PacketDecoder.java:21)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
... 19 more
服务器main(String[] args)
EventLoopGroup eventLoopGroup = epoll ? (EventLoopGroup) new EpollEventLoopGroup() : (EventLoopGroup) new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(eventLoopGroup);
serverBootstrap.channel(epoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class);
serverBootstrap.childHandler(new ChannelInitializer<Channel>() {
protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(new NetworkHandler());
}
});
channel = serverBootstrap.bind(networkConfiguration.getPort()).sync().channel();
channel.closeFuture().syncUninterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
eventLoopGroup.shutdownGracefully();
}
客户端主要(String[] args):
EventLoopGroup eventLoopGroup = epoll ? (EventLoopGroup) new EpollEventLoopGroup() : (EventLoopGroup) new NioEventLoopGroup();
try {
io.netty.bootstrap.Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup);
bootstrap.channel(epoll ? EpollSocketChannel.class : NioSocketChannel.class);
bootstrap.handler(new ChannelInitializer<Channel>() {
protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(new NetworkHandler());
}
});
channel = bootstrap.connect(networkConfiguration.getMasterHostname(), networkConfiguration.getMasterPort()).sync().channel();
packetCaller = new PacketCaller(channel);
packetCaller.sendPacket(new PacketOutVerify(networkConfiguration.getWrapperName(), networkConfiguration.getKey()));
channel.closeFuture().syncUninterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
eventLoopGroup.shutdownGracefully();
}
NetworkHandler 中的 channelActive:
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.pipeline().addLast(new PacketEncoder());
ctx.pipeline().addLast(new PacketDecoder());
this.waitingForRegistration.add(ctx.channel());
}
数据包解码器
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> output) throws Exception {
int id = byteBuf.readInt();
Class<? extends Packet> clazz = Wrapper.IN_PACKETS.get(id);
if (clazz == null) {
throw new NullPointerException("Could not find packet by id " + id);
}
Packet packet = clazz.newInstance();
packet.read(byteBuf, ctx.channel());
}
数据包编码器
public class PacketEncoder extends MessageToByteEncoder<Packet> {
@Override
protected void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf output) throws Exception {
int id = Wrapper.OUT_PACKETS.indexOf(packet.getClass());
if(id == -1)
throw new NullPointerException("Couldn't find packet of " + packet.getClass().getName());
output.writeInt(id);
packet.write(output, ctx.channel());
}
}
所以有多个问题。
首先在 PacketDecoder
中,您需要先检查是否有 4 个字节可读,然后再尝试调用 byteBuf.readInt()
。所以像:
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> output) throws Exception {
if (byteBuf.readableBytes() < 4) {
return;
}
int id = byteBuf.readInt();
...
}
其次,在您的 Packet.read()
方法中,您还需要确保有足够的字节可读,如果没有,请稍后重试
我目前正在编写一个通过数据包进行通信的系统。这也有效。我有一台服务器和理论上无限的客户端。当我只启动一个客户端时,它工作得很好,但是当我启动多个客户端时,我总是在程序运行 2-3 分钟后出现 java.lang.IndexOutOfBoundsException
异常。
异常
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(77) + length(36) exceeds writerIndex(112): PooledUnsafeDirectByteBuf(ridx: 77, widx: 112, cap: 112)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:478)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:795)
at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:480)
at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:378)
at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IndexOutOfBoundsException: readerIndex(77) + length(36) exceeds writerIndex(112): PooledUnsafeDirectByteBuf(ridx: 77, widx: 112, cap: 112)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1442)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1428)
at io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:895)
at io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:903)
at eu.diamondcloudservice.wrapper.packets.incoming.PacketInCloudServerConnect.read(PacketInCloudServerConnect.java:79)
at eu.diamondcloudservice.wrapper.network.PacketDecoder.decode(PacketDecoder.java:21)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
... 19 more
服务器main(String[] args)
EventLoopGroup eventLoopGroup = epoll ? (EventLoopGroup) new EpollEventLoopGroup() : (EventLoopGroup) new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(eventLoopGroup);
serverBootstrap.channel(epoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class);
serverBootstrap.childHandler(new ChannelInitializer<Channel>() {
protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(new NetworkHandler());
}
});
channel = serverBootstrap.bind(networkConfiguration.getPort()).sync().channel();
channel.closeFuture().syncUninterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
eventLoopGroup.shutdownGracefully();
}
客户端主要(String[] args):
EventLoopGroup eventLoopGroup = epoll ? (EventLoopGroup) new EpollEventLoopGroup() : (EventLoopGroup) new NioEventLoopGroup();
try {
io.netty.bootstrap.Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup);
bootstrap.channel(epoll ? EpollSocketChannel.class : NioSocketChannel.class);
bootstrap.handler(new ChannelInitializer<Channel>() {
protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(new NetworkHandler());
}
});
channel = bootstrap.connect(networkConfiguration.getMasterHostname(), networkConfiguration.getMasterPort()).sync().channel();
packetCaller = new PacketCaller(channel);
packetCaller.sendPacket(new PacketOutVerify(networkConfiguration.getWrapperName(), networkConfiguration.getKey()));
channel.closeFuture().syncUninterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
eventLoopGroup.shutdownGracefully();
}
NetworkHandler 中的 channelActive:
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.pipeline().addLast(new PacketEncoder());
ctx.pipeline().addLast(new PacketDecoder());
this.waitingForRegistration.add(ctx.channel());
}
数据包解码器
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> output) throws Exception {
int id = byteBuf.readInt();
Class<? extends Packet> clazz = Wrapper.IN_PACKETS.get(id);
if (clazz == null) {
throw new NullPointerException("Could not find packet by id " + id);
}
Packet packet = clazz.newInstance();
packet.read(byteBuf, ctx.channel());
}
数据包编码器
public class PacketEncoder extends MessageToByteEncoder<Packet> {
@Override
protected void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf output) throws Exception {
int id = Wrapper.OUT_PACKETS.indexOf(packet.getClass());
if(id == -1)
throw new NullPointerException("Couldn't find packet of " + packet.getClass().getName());
output.writeInt(id);
packet.write(output, ctx.channel());
}
}
所以有多个问题。
首先在 PacketDecoder
中,您需要先检查是否有 4 个字节可读,然后再尝试调用 byteBuf.readInt()
。所以像:
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> output) throws Exception {
if (byteBuf.readableBytes() < 4) {
return;
}
int id = byteBuf.readInt();
...
}
其次,在您的 Packet.read()
方法中,您还需要确保有足够的字节可读,如果没有,请稍后重试