摘要:LineBasedFrameDecoder是一种解码器,专门用于以换行符为分割的消息的解码,能够处理\n和\r\n的换行符。
使用TCP协议的应用中,读取消息时会发生粘包和拆包的问题(参考《TCP粘包与拆包分析及解决之道》),所以我们需要在自己的应用中处理粘包和拆包,解决粘包和拆包的方法有:
  1. 消息定长,如固定协议包长度是100字节,如果不够,包尾空格补位;
  2. 包尾增加换行符或者其它符号进行分割,如FTP协议;
  3. 将消息分为消息头和消息体,在消息头固定的位置增加一个字段,表示消息的总长度(或消息的长度),参照TCP协议;
  4. 使用更复杂的应用层协议;

LineBasedFrameDecoder是Netty提供的一种解码器,专门用于以换行符为分割的消息的解码,能够处理\n和\r\n的换行符,显然它对应上面第2点方法来解决粘包和拆包的问题。继承关系如下所示:
可以看到LineBasedFrameDecoder继承了ByteToMessageDecoder,这样对于转换字节为POJO对象的底层工作就交给ByteToMessageDecoder类来实现了,LineBasedFrameDecoder类只需要负责对消息的字节流进行解包即可。

注:在Netty中实现的其它解码器继承的结构和实现解码的代码结构也很类似,一般都会继承ByteToMessageDecoder,代码结构上也很类似。

LineBasedFrameDecoder中真正实现解包功能的是decode()方法,代码如下所示:
@Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in,
     List<Object> out) throws Exception {
    Object decoded = decode(ctx, in);
    if (decoded != null) {
        out.add(decoded);
    }
}
可以看到decode中调用了decode(ChannelHandlerContext ctx, ByteBuf buffer) 来处理解包,整个处理流程如下所示:


在这个过程中,我们需要注意的是包残余的情况。包与包之间是通过换行符分隔的,当我们读取的字节流中没有换行符,并且长度大于最大长度maxLength时,我们需要把字节流丢弃,然后重新读取。当再次读取到字节流后,如果字节流中包含了换行符,那么由于这个包的一部分字节在上次读取时被丢弃了,那么现在读取的起点到换行符之间的字节已经不是一个完整的包了,或者说由于这个包太长了不符合我们的协议规定,所以第二次读取的字节流中换行符之前的字节也应该被丢弃。这也是discarding字段的使用意义。

下面通过一些具体的例子来说明一下,假如设置的maxLength=12,我们需要读取的字节流是:
hello world\r\nThis is LinebasedFrameDecoder\r\nThis is decoder\r\n
首先我们需要知道当前可读取的字节中是否包含换行符(\n或\r\n),findEndOfLine()方法已经实现这个功能,可以自行阅读源码。假设每次读取的字节如下所示:
  1. 第一次读取10字节,即hello worl,没有找到换行符,按照流程处理应该是返回null,读指针位置保持不变readIndex=0;
  2. 第二次读取6字节,即d\r\nThi,找到换行符到起始位置长度为11,小于maxLength,那么返回一个完整包消息hello world,并且设置readIndex=13(跳过换行符);
  3. 第三次读取13字节,即s is Linebase,可读字节长度为16,由于没有找到换行符且字节流长度大于maxLength,那么这个包是一个不符合规定的包,把读取到的包消息丢弃,设置discarding=true,readIndex=29,下一个要读取的字符是F;
  4. 第四读取13字节,可读字节长度为13字节,找到换行符且discarding=true,说明这些字节是包的残余消息,那么换行符前的字节也应该丢弃,设置discarding=false,readIndex=42,下一个读取的字符是T;
LineBasedFrameDecoder的规则是比较简单的,它也是DelimiterBasedFrameDecoder解码器的一个特例,熟悉了LineBasedFrameDecoder的处理过程,再去看DelimiterBasedFrameDecoder 也完全不是问题。LineBasedFrameDecoder给我们演示了读半包的处理手段,也展示了一种最简单的获取整包消息的方法,掌握LineBasedFrameDecoder后能够让我们更加容易理解netty各个解码器的原理。

版权说明:如无特殊说明,文章均为本站原创,如需转载请注明出处

本文标题:Netty5源码之LineBasedFrameDecoder

本文地址:http://www.wolfbe.com/detail/201609/371.html

本文标签: decoder netty java

相关文章

感谢您的支持,朗度云将继续前行

扫码打赏,金额随意

温馨提醒:打赏一旦完成,金额无法退还,请谨慎操作!

扫二维码 我要反馈 回到顶部