LengthFieldBasedFrameDecoder和LengthFieldPrepender在Netty提供的codec中有举足轻重的作用。其目的就是为了解决粘包问题。通过前置发送帧长度字段来表示数据的长度,进而根据接收帧的长度字段进行解码,得到真实数据。
【1】阅读前要知悉:
- Netty框架处理事件的原理(基本上都是
ChannelHandlerContext传递事件到下一个ChannelHandler中) - 如
ctx.write()是此时的ChannelHandler中ChannelHandlerContext的的写事件,因为是写事件,这个事件对象就会传递给下一个ChannelOutboundHandler的写事件处理,即ctx.write()
【2】看一下LengthFieldBasedFrameDecoder和LengthFieldPrepender的继承关系
-
LengthFieldBasedFrameDecoder继承关系
由上图可知,LengthFieldBasedFrameDecoder继承自ByteToMessageDecoder,ByteToMessageDecoder属于入站消息处理器,当有消息读入时就会调用其channelRead方法,把消息传递到下一个ChannelInboundHandler。 -
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()传递给下一个出站处理器中。
- 在
LengthFieldBasedFrameDecoder的decode方法上设置断点。
- 在调试窗口中就可以看到详细的参数数据变化,如下图所示。
读到一个复合的ByteBuf,58个字节缓存区,正好对应上边编码的长度字段4个字节和54个字节数据。返回的帧就是去掉长度字段的数据帧,长度为54字节。经过ByteToMessageDecoder的channelRead方法将数据传递给下一个入站处理器。
- 至此解码工作完成。详情还需要自己动手把握。