我在日志中收到此警告:

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的方式。

09-04 04:59