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
我在日志中收到此警告:
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