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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40370114/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 05:09:57  来源:igfitidea点击:

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

javaexceptionclient-servernetty

提问by kaiser

I got this warning in my log:

我在日志中收到此警告:

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

That are my ChannelHandlers:

那是我的 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));
}

My TimeoutHandler throws a TimeoutException if there was no read for the last 15 seconds. And in my last handler, the ServerCommunicationHandler, i have overridden the exeptionCaught function:

如果过去 15 秒内没有读取,我的 TimeoutHandler 会抛出 TimeoutException。在我的最后一个处理程序 ServerCommunicationHandler 中,我覆盖了 exeptionCaught 函数:

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    ctx.close();
}

So if i understand right, i do not rethrow the exception to the end of the pipeline, because my last handler processes the exception correctly, doesn't it?

因此,如果我理解正确,我不会将异常重新抛出到管道的末尾,因为我的最后一个处理程序正确地处理了异常,不是吗?

Why do i get this warning?

为什么我会收到此警告?

I use Netty 4.1.6.Final

我使用 Netty 4.1.6.Final

采纳答案by Chris O'Toole

This can be caused by your TimeoutHandler throwing the TimeoutException after the channel has been closed. It can happen because once a channel is closed all the ChannelHandlers will be removed (unregistered), but the ChannelHandlerContext still has a reference to the pipeline, so if you close a channel and then fire an event on the ctxthere won't be any handlers to intercept the event.

这可能是由于您的 TimeoutHandler 在通道关闭后抛出 TimeoutException 引起的。之所以会发生这种情况,是因为一旦通道关闭,所有 ChannelHandlers 都将被删除(未注册),但 ChannelHandlerContext 仍然具有对管道的引用,因此如果关闭通道然后在该通道上触发事件,ctx则不会有任何处理程序拦截事件。

I was able to recreate the error you see by writing a simple/broken TimeoutHandler:

我能够通过编写一个简单/损坏的 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);
    }
}

Have you considered using the Netty ReadTimeoutHandlerinstead of writing your own?

您是否考虑过使用 Netty ReadTimeoutHandler而不是自己编写?

If you really want to write your own, make sure you are canceling your timer when the channel goes inactive. You can see how IdleStateHandler does this.

如果您真的想自己编写,请确保在频道处于非活动状态时取消您的计时器。您可以看到IdleStateHandler如何做到这一点

回答by mengli

Maybe it's an exception thrown due to incomplete data received? My project also encountered this problem recently, because the received data code is GBK and I use utf8, so when intercepting the data in the corresponding location, I threw a subscript out of range error and caused this error.

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

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

既不是英文也不能用 ISO-8859 字符集打印的错误消息的屏幕截图