Getting Netty The exceptionCaught () event was fired, and it was reached at the tail of the TextWebsocketEncoder pipeline

I try to execute a simple web socket decode and then encode, but I get this exception when it passes the TextWebsocketDecoder handler:

io.netty.channel.DefaultChannelPipeline$TailContext exceptionCaught WARNING: 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. io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1 at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:101) at io.netty.buffer.DefaultByteBufHolder.release(DefaultByteBufHolder.java:73) at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:59) at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:112) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:318) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:304) at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:318) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:304) at io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler$1.channelRead(WebSocketServerProtocolHandler.java:147) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:318) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:304) at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:318) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:304) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:276) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:263) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:318) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:304) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:846) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354) at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112) at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137) at java.lang.Thread.run(Thread.java:745) 

I have a simple initializer that works before TextWebsocketEncoder:

 public class ServerInitializer extends ChannelInitializer<Channel> { private final ChannelGroup group; public GameServerInitializer(ChannelGroup group) { this.group = group; } @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HttpServerCodec()); pipeline.addLast(new HttpObjectAggregator(64 * 1024)); pipeline.addLast(new ChunkedWriteHandler()); pipeline.addLast(new HttpRequestHandler("/ws")); pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); pipeline.addLast(new TextWebSocketFrameHandler(group)); pipeline.addLast("textWebsocketDecoder",new TextWebsocketDecoder()); pipeline.addLast("textWebsocketEncoder",new TextWebsocketEncoder()); } } 

TextWebSocketFrameHandler

 public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame>{ private final ChannelGroup group; public TextWebSocketFrameHandler(ChannelGroup group) { this.group = group; } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) { ctx.pipeline().remove(HttpRequestHandler.class); group.writeAndFlush(new TextWebSocketFrame("Client " + ctx.channel() + " joined")); group.add(ctx.channel()); } else { super.userEventTriggered(ctx, evt); } } @Override public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { ctx.fireChannelRead(msg); //group.writeAndFlush(msg.retain()); } } 

and this is TextWebsocketDecoder and TextWebsocketEncoder:

TextWebsocketDecoder:

 public class TextWebsocketDecoder extends MessageToMessageDecoder<TextWebSocketFrame> { @Override protected void decode(ChannelHandlerContext ctx, TextWebSocketFrame frame, List<Object> out) throws Exception { String json = frame.text(); JSONObject jsonObject = new JSONObject(json); int type = jsonObject.getInt("type"); JSONArray msgJsonArray = jsonObject.getJSONArray("msg"); String user = msgJsonArray.getString(0); String pass = msgJsonArray.getString(1); String connectionkey = msgJsonArray.getString(2); int timestamp = jsonObject.getInt("timestamp"); JSONObject responseJson = new JSONObject(); responseJson.put("type",Config.LOGIN_SUCCESS); responseJson.put("connectionkey",connectionkey); out.add(responseJson); // After This im getting the exception !!! } } 

TextWebsocketEncoder

 import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; public class TextWebsocketEncoder extends MessageToMessageEncoder<JSONObject> { @Override protected void encode(ChannelHandlerContext arg0, JSONObject arg1, List<Object> out) throws Exception { String json = arg1.toString(); out.add(new TextWebSocketFrame(json)); } } 
+6
source share
2 answers

An exception

Inside your TextWebSocketFrameHandler, you call ctx.fireChannelRead(msg); , this sends the message up 1 chain, however MessageToMessageDecoder not ready for this. To explain this problem, I need to explain how MessageToMessageDecoder works.

MessageToMessageDecoder works by catching each message from the upstream and passing it to its own code, your custom code processes the work, and mtmd handles the closure of the resource you submitted.

Since you are passing the link to the other side, you are effectively closing the WebSocketFrame several times, causing errors. MessageToMessageDecoder even warns you about this in javadoc .

To solve this problem, follow the instructions in the manual and make our channel Read the following:

 @Override public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { msg.retain(); // ferrybig: fixed bug http://stackoverflow.com/q/34634750/1542723 ctx.fireChannelRead(msg); //group.writeAndFlush(msg.retain()); } 

Problem sending back

In your comments, you stated that the code does not send anything. This is expected, since your pipeline only consumes data and passes it to the chain. To fix this, you will need to recycle in your conveyor.

  • We need to change the order of the json-webframe decoder and encoder:

     pipeline.addLast("textWebsocketDecoder",new TextWebsocketEncoder()); pipeline.addLast("textWebsocketEncoder",new TextWebsocketDecoder()); 

    This is due to the fact that your decoder generates an output that will send back ↑ a chain of handlers, this output will not be perceived by the encoder if the decoder was above this. (Your decoder should not be called a decoder after the name netty)

  • We need to change your decoder to send the generated data actually back ↑ the chain instead of ↓ into a nonexistent void.

    To make these changes, we will allow TextWebSocketDecoder to extend the ChannelInboundHandlerAdapter instead of MessageToMessageDecoder<TextWebSocketFrame> , because we are processing messages, but not passing them to another handler.

    We change the signature of the decoding method to channelRead(ChannelHandlerContext ctx, Object msg) and add the template code:

     public void channelRead(ChannelHandlerContext ctx, Object msg) /* throws Exception */ TextWebSocketFrame frame = (TextWebSocketFrame) msg; try { /* Remaining code, follow the steps further of see end result */ } finally { frame.release(); } } 
  • We adapt our code to pipe the result instead of down:

     public void channelRead(ChannelHandlerContext ctx, Object msg) /* throws Exception */ TextWebSocketFrame frame = (TextWebSocketFrame) msg; try { String json = frame.text(); JSONObject jsonObject = new JSONObject(json); int type = jsonObject.getInt("type"); JSONArray msgJsonArray = jsonObject.getJSONArray("msg"); String user = msgJsonArray.getString(0); String pass = msgJsonArray.getString(1); String connectionkey = msgJsonArray.getString(2); int timestamp = jsonObject.getInt("timestamp"); JSONObject responseJson = new JSONObject(); responseJson.put("type",Config.LOGIN_SUCCESS); responseJson.put("connectionkey",connectionkey); ctx.writeAndFlush(responseJson) } finally { frame.release(); } } 

Note that you may be tempted to remove our previous code from the exception, but it will also perform undefined behavior when run under the asynchronous nature of netty.

+3
source

You are using SimpleChannelInboundHandler , which automatically displays the data received in accordance with the documentation.

So, when you call ctx.fireChannelRead(msg); to transfer msg to other handlers on the pipeline, the besauce msg problem occurs.

To fix this, you can use the ChannelInboundHandlerAdapter , or you can stop the SimpleChannelInboundHandler auto-release process by calling the appropriate constructor, or you can call ReferenceCountUtil.retain(msg); before shooting down the conveyor belt.

See the SimpleChannelInboundHandler documentation here: http://netty.io/4.0/api/io/netty/channel/SimpleChannelInboundHandler.html

and read links to counted objects here (new concept of netty 4): http://netty.io/wiki/reference-counted-objects.html

+1
source

All Articles