我刚开始使用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
中做错了吗?
答案 0 :(得分:6)
看看ByteBuf :: retain()