我的自定义网络解码器中的IllegalReferenceCount

时间:2014-02-25 09:22:22

标签: java netty

我刚开始使用Netty(使用4.0.15.Final)。我想从现有的硬件设备读取消息,该设备可以使用专有协议。我已经实现了如下:

public class Xml2StreamProtocolDecoder extends ByteToMessageDecoder
{
    private static final int LENGTH_OF_START_SENTINEL_IN_BYTES = 1;
    private static final int LENGTH_OF_END_SENTINEL_IN_BYTES = 1;
    private static final int LENGTH_OF_LENGTH_FIELD_IN_BYTES = 4;

    @Override
    protected void decode( ChannelHandlerContext ctx, ByteBuf in, List<Object> out ) throws Exception
    {
        if( in.readableBytes() > LENGTH_OF_START_SENTINEL_IN_BYTES + LENGTH_OF_LENGTH_FIELD_IN_BYTES)
        {
            short startSentinel = in.readUnsignedByte();
            if (startSentinel != 0x01)
            {
                throw new CorruptedFrameException( "startsentinel not as expected, was " + startSentinel + " while we expect 0x01" );
            }

            int messageLength = getMessageLength( in );
            if( in.readableBytes() >= messageLength + LENGTH_OF_END_SENTINEL_IN_BYTES )
            {
                ByteBuf result = in.slice( in.readerIndex(), messageLength );
                in.skipBytes( messageLength );
                short endSentinel = in.readUnsignedByte();
                if( endSentinel != 0x00 )
                {
                    throw new CorruptedFrameException( "endsentinel not as expected, was " + endSentinel + " while we expect 0x00" );
                }
                out.add( result );
            }
            else
            {
                // Not enough bytes yet in the frame. Wait on next pass with more bytes.
            }
        }
        else
        {
            // Not enough bytes yet to read out the length of the frame. Wait on next pass with more bytes.
        }
    }

    private int getMessageLength( ByteBuf in )
    {
        int msglen1 = in.readUnsignedByte();
        int msglen2 = in.readUnsignedByte();
        int msglen3 = in.readUnsignedByte();
        int msglen4 = in.readUnsignedByte();

        return ((msglen4 * 256 * 256 * 256) + (msglen3 * 256 * 256) + (msglen2 * 256) + msglen1);
    }
}

我的单元测试工作得很好:

ByteBuf input = Unpooled.buffer();
input.writeBytes( .... );
Xml2StreamProtocolDecoder decoder = new Xml2StreamProtocolDecoder();
EmbeddedChannel channel = new EmbeddedChannel( decoder );
channel.writeInbound( input );
assertThat(channel.inboundMessages()).isNotNull().hasSize( 2 );

然而,当我在管道中添加第二个解码器(这是一个标准的Netty类)时,将字节转换为字符串,如下所示:

EmbeddedChannel channel = new EmbeddedChannel( decoder, 
                                               new StringDecoder( Charset.forName( "UTF-8" ) ) );

然后单元测试失败,出现以下异常:

Feb 25, 2014 10:11:26 AM io.netty.channel.embedded.EmbeddedChannel recordException
WARNING: More than one exception was raised. Will report only the first one and log others.
io.netty.handler.codec.DecoderException: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:99)
    at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:338)
    at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:324)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:153)
    at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:338)
    at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:324)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785)
    at io.netty.channel.embedded.EmbeddedChannel.writeInbound(EmbeddedChannel.java:169)
    at com.flir.its.test.Xml2StreamProtocolDecoder2Test.testWith2Messages(Xml2StreamProtocolDecoder2Test.java:188)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:640)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:627)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:798)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1102)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:137)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:121)
    at org.testng.TestRunner.runWorkers(TestRunner.java:1009)
    at org.testng.TestRunner.privateRun(TestRunner.java:683)
    at org.testng.TestRunner.run(TestRunner.java:553)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:311)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:306)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:268)
    at org.testng.SuiteRunner.run(SuiteRunner.java:217)
    at org.testng.TestNG.runSuite(TestNG.java:1062)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:956)
    at org.testng.TestNG.run(TestNG.java:874)
io.netty.handler.codec.DecoderException: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:99)
    at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:338)
    at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:324)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:153)
    at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:338)
    at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:324)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785)
    at io.netty.channel.embedded.EmbeddedChannel.writeInbound(EmbeddedChannel.java:169)
    at com.flir.its.test.Xml2StreamProtocolDecoder2Test.testWith2Messages(Xml2StreamProtocolDecoder2Test.java:188)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:640)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:627)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:798)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1102)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:137)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:121)
    at org.testng.TestRunner.runWorkers(TestRunner.java:1009)
    at org.testng.TestRunner.privateRun(TestRunner.java:683)
    at org.testng.TestRunner.run(TestRunner.java:553)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:311)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:306)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:268)
    at org.testng.SuiteRunner.run(SuiteRunner.java:217)
    at org.testng.TestNG.runSuite(TestNG.java:1062)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:956)
    at org.testng.TestNG.run(TestNG.java:874)
    at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:75)
    at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:120)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:115)
    at io.netty.buffer.AbstractDerivedByteBuf.release(AbstractDerivedByteBuf.java:50)
    at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:68)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:91)
    ... 35 more
    at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:75)
    at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:120)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:115)
    at io.netty.buffer.AbstractDerivedByteBuf.release(AbstractDerivedByteBuf.java:50)
    at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:68)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:91)
    ... 35 more

为什么会这样?我在Xml2StreamProtocolDecoder中做错了吗?

1 个答案:

答案 0 :(得分:6)

看看ByteBuf :: retain()