我在日志中收到此警告:
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
最佳答案
这可能是由于关闭通道后,您的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的方式。