Netty - 触发了一个 exceptionCaught() 事件,它到达了管道的尾部

Netty - An exceptionCaught() event was fired, and it reached at the tail of the pipeline

我在日志中收到此警告:

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。它可能会发生,因为一旦通道关闭,所有 ChannelHandlers 都将被删除(未注册),但 ChannelHandlerContext 仍然具有对管道的引用,因此如果您关闭通道然后在 ctx 上触发事件,则获胜' 成为拦截事件的任何处理程序。

我能够通过编写 simple/broken 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

可能是收到的数据不完整抛出的异常? 我的项目最近也遇到这个问题,因为接收到的数据编码是GBK,而我使用的是utf8,所以在截取相应位置的数据时,抛出下标超出范围的错误,导致了这个错误。

screenshot of error message which is neither English nor printable with ISO-8859 charset