我在日志中收到了这个警告:
Nov 02, 2016 12:07:20 AM 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.
java.util.concurrent.TimeoutException
这是我的ChannelHandlers:
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
ch.pipeline().addLast(new TimeoutHandler(TIME_OUT_SECONDS));
ch.pipeline().addLast(new ServerCommunicationHandler(messageHandler));
}
如果最近15秒没有读取,我的TimeoutHandler会抛出TimeoutException。 在我的最后一个处理程序ServerCommunicationHandler中,我已经覆盖了exeptionCaught函数:
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ctx.close();
}
因此,如果我理解正确,我不会将异常重新抛出到管道的末尾,因为我的上一个处理程序正确处理了异常,不是吗?
为什么我会收到此警告?
我使用Netty 4.1.6.Final
答案 0 :(得分:1)
这可能是由于TimeoutHandler在关闭通道后抛出TimeoutException。这可能发生,因为一旦一个频道关闭,所有的ChannelHandler都将被删除(未注册),但ChannelHandlerContext仍然有一个对该管道的引用,所以如果你关闭一个频道,然后在ctx
上发起一个事件就赢了是拦截事件的任何处理者。
我能够通过编写一个简单/破坏的TimeoutHandler重新创建您看到的错误:
@RequiredArgsConstructor
private static class TimeoutHandler extends ChannelInboundHandlerAdapter {
private final int timeoutSeconds;
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
ctx.executor().schedule(
// This exception can still be fired once the channel is closed and all handlers removed
() -> ctx.fireExceptionCaught(new TimeoutException()),
timeoutSeconds, TimeUnit.SECONDS);
super.channelRegistered(ctx);
}
}
您是否考虑过使用Netty ReadTimeoutHandler而不是自己编写?
如果您真的想自己编写,请确保在频道处于非活动状态时取消定时器。你可以看到IdleStateHandler does this的方式。
答案 1 :(得分:0)
也许这是由于接收到的数据不完整而引发的异常? 我的项目最近也遇到了这个问题,因为接收到的数据代码是GBK,并且我使用的是utf8,因此在拦截相应位置的数据时,我将下标超出范围并抛出了该错误。
screenshot of error message which is neither English nor printable with ISO-8859 charset