【问题标题】:Netty SslHandler throws IllegalReferenceCountExceptionNetty SslHandler 抛出 IllegalReferenceCountException
【发布时间】:2018-05-04 08:18:11
【问题描述】:

我正在使用 netty 4.0.36.Final 编写客户端-服务器应用程序

一位测试工程师在客户端遇到了这个问题:

io.netty.handler.codec.DecoderException: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:418)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:245)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:292)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:278)
    at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:266)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:292)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:278)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:962)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:528)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:485)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:399)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:371)
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
    at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
    at java.base/java.lang.Thread.run(Unknown Source)
Caused by: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:101)
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1072)
    at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:904)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:387)
    ... 15 common frames omitted

渠道管道:

@Override
public void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();
    pipeline.addLast(sslContext.newHandler(ch.alloc()));
    pipeline.addLast(new AsnMessageDecoder());
    pipeline.addLast(new AsnMessageEncoder());
    pipeline.addLast(dataChannelHandler);
}

在某个时候,我向管道添加了另一个处理程序:

channel.pipeline().addFirst("idleStateHandler", new IdleStateHandler(180, 0, 0));

有两个ChannelInboundHandler

public class AsnMessageDecoder extends ReplayingDecoder {
private static final Logger log = LoggerFactory.getLogger(AsnMessageDecoder.class);
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
    DERCoder coder = Asn.getDERCoder();
    coder.disableEncoderDebugging();
    coder.disableDecoderDebugging();
    coder.enableEncoderConstraints();
    coder.enableDecoderConstraints();
    coder.enableAutomaticEncoding();
    coder.enableAutomaticDecoding();
    coder.enableContainedValueEncoding();
    coder.enableContainedValueDecoding();
    try (ByteBufInputStream is = new ByteBufInputStream(in)) {
        out.add(coder.decode(is, new Message()));
    } catch (Exception e) {
        log.error("Failed to decode message", e);
    }
}

还有一个:

abstract class BaseChannelHandler<T extends ChannelContext> extends SimpleChannelInboundHandler<Message> {
private final Logger log = LoggerFactory.getLogger(getClass());

private final T channelContext;
private final ClientConfiguration clientConfiguration;
private final Writer writer;
private final ClientService service;

BaseChannelHandler(T channelContext,
                   ClientConfiguration clientConfiguration,
                   Writer writer,
                   ClientService service) {
    this.channelContext = channelContext;
    this.clientConfiguration = clientConfiguration;
    this.writer = writer;
    this.service = service;
}

@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    log.debug("{} channelRegistered", getClass().getSimpleName());
}

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
    log.debug("{} channelActive", getClass().getSimpleName());
    channelContext.connectState();
}

@Override
protected void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception {
    log.debug("{} channelRead0 msg = {}", getClass().getSimpleName(), msg);
    channelContext.handleMessage(msg);
    if (clientConfiguration.isWritingOutputEnabled()) {
        writer.writeXml(msg);
    }
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    log.error(getClass().getSimpleName() + " exceptionCaught", cause);
    ctx.close();
    service.stop();
}

@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    log.debug("{} channelInactive", getClass().getSimpleName());
}

@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
    log.debug("{} channelUnregistered", getClass().getSimpleName());
}

@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    if (evt instanceof IdleStateEvent) {
        ctx.disconnect();
    }
}

我无法重现问题。在我的本地机器上它工作正常。查看 wirweshark 并没有给我任何提示。它看起来像正常的断开连接。 我不太确定下一步该做什么来解决这个问题。你能给我一些关于下一步解决这个问题的建议吗?

【问题讨论】:

  • 我怀疑你没有正确地增加你的一个处理程序中的引用计数。你能展示你的管道和自定义处理程序吗?
  • 嗨,诺曼。谢谢你的答复。我无法提供我的 hadlers 的代码,但我可以向您展示管道。我编辑了初始消息。查看堆栈跟踪,似乎这个读取事件通过了 IdleStateHandler 并在 SslHandler 中引发了异常。两者都是 netty 的类,自定义处理程序不参与。会不会是 netty SslHandler 的 bug?
  • 当然这可能是一个网络错误,但我认为不太可能。虽然异常发生在 SslHandler 中,但它可能只显示在那里,因为它仍然具有对缓冲区的引用并尝试使用它。我怀疑你以某种方式双重释放缓冲区。所以请告诉我你ChannelInboundHandler(和子类)
  • 我添加了两个用于管道的ChannelInboundHandler
  • 哇,我刚刚注意到您运行的是超级旧版本的 netty,所以也许可以尝试先升级到 4.0.56.Final ? 4.0.x 也是 EOL,而 4.1.x 是您应该使用的版本;)请在完成后报告。

标签: java networking client-server netty


【解决方案1】:

所以这似乎是 netty 版本中的一个错误(它很旧)。升级到 4.1.24.Final 修复它。

【讨论】:

    猜你喜欢
    • 2012-06-22
    • 1970-01-01
    • 2019-01-13
    • 2020-07-13
    • 2014-09-15
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多