LengthFieldBasedFrameDecoder
和LengthFieldPrepender
在Netty提供的codec中有举足轻重的作用。其目的就是为了解决粘包问题。通过前置发送帧长度字段来表示数据的长度,进而根据接收帧的长度字段进行解码,得到真实数据。
【1】阅读前要知悉:
Netty框架处理事件的原理(基本上都是ChannelHandlerContext
传递事件到下一个ChannelHandler
中)
如ctx.write()
是此时的ChannelHandler
中ChannelHandlerContext
的的写事件,因为是写事件,这个事件对象就会传递给下一个ChannelOutboundHandler
的写事件处理,即ctx.write()
【2】看一下LengthFieldBasedFrameDecoder
和LengthFieldPrepender
的继承关系
1.LengthFieldBasedFrameDecoder
继承关系
由上图可知, LengthFieldBasedFrameDecoder
继承自ByteToMessageDecoder
,ByteToMessageDecoder
属于入站消息处理器,当有消息读入时就会调用其channelRead
方法,把消息传递到下一个ChannelInboundHandler
。
2,LengthFieldPrepender
继承关系
由上图可知, LengthFieldPrepender
继承自MessageToMessageEecoder<ByteBuf>
,MessageToMessageEecoder<ByteBuf>
属于出站消息处理器,当有消息写入时就会调用其write
方法,把消息传递到下一个ChannelOutboundHandler
。
【3】通过调试看懂LengthFieldBasedFrameDecoder
和LengthFieldPrepender
的内部原理
关于LengthFieldBasedFrameDecoder
和LengthFieldPrepender
二者的作用在官方API文档中就有详细地介绍,在这不再赘述。我们需要搞清楚地内部是怎么来实现的。如何加的长度前缀字段,又如何把消息帧解码?在这里只给出方法,具体的还需要读者开发者详细地做调试。哪里不会调哪里。
3. 在LengthFieldPrepender
的encode
方法中断点,如图所示。点击运行。
- 在调试窗口中就可以看到详细的参数数据变化,如下图所示。
可以看到编码后的List列表中有两个ByteBuf
存在,之后这两个ByteBuf
在MessageToMessageEecoder<ByteBuf>
的write
方法中经ctx传递。
- 再看后续调试。
可以看到程序运行到MessageToMessageEecoder<ByteBuf>
的write
方法中来,进而看到两个ByteBuf
被在loop中经ctx.write()
传递给下一个出站处理器中。
2.在LengthFieldBasedFrameDecoder
的decode
方法上设置断点。
在调试窗口中就可以看到详细的参数数据变化,如下图所示。
读到一个复合的ByteBuf
,58个字节缓存区,正好对应上边编码的长度字段4个字节和54个字节数据。返回的帧就是去掉长度字段的数据帧,长度为54字节。经过ByteToMessageDecoder
的channelRead
方法将数据传递给下一个入站处理器。
3.至此解码工作完成。详情还需要自己动手把握。