Netty4.xNetty源码分析之LineBasedFrameDecoder

Posted 程序员小毛驴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Netty4.xNetty源码分析之LineBasedFrameDecoder相关的知识,希望对你有一定的参考价值。

   在上一篇:【游戏开发】TCP粘包/拆包问题的解决办法(二)文章中,我们在给ServerHandler之前添加了2个解码器LineBasedFrameDecoder和StringDecoder解决了服务器端粘包问题。今天我们就从源码上来分析LineBasedFrameDecoder。

一、LineBasedFrameDecoder

   1.1 工作原理

  LineBasedFrameDecoder是回车换行解码器,如果用户发送的消息以回车换行符作为消息结束的标识,则可以直接使用Netty的LineBasedFrameDecoder对消息进行解码。它会依次遍历ByteBuf中的可读字节,判断看是否有“\\n”或者“\\r\\n”,如果有,就以此位置为结束位置,从可读索引到结束位置区间的字节就组成了一行。它是以换行符为结束标志的解码器,支持携带结束符或者不携带结束符两种解码方式,同时支持配置单行的最大长度。如果连续读取到最大长度后仍然没有发现换行符,就会抛出异常,同时忽略掉之前读到的异常码流。防止由于数据报没有携带换行符导致接收到ByteBuf无限制积压,引起系统内存溢出。

   1.2 变量解析

/** Maximum length of a frame we're willing to decode.  */
    private final int maxLength;
    /** Whether or not to throw an exception as soon as we exceed maxLength. */
    private final boolean failFast;
    private final boolean stripDelimiter;
    /** True if we're discarding input because we're already over maxLength.  */
    private boolean discarding;
    private int discardedBytes;

变量名称说明
maxLength读取的最大长度,如果连续读取到最大长度后仍然没有发现换行符,就会抛出异常,同时忽略掉之前读到的异常码流
failFast如果设置成true,当发现解析的数据超过maxLenght就立马报错,否则当整个帧的数据解析完后才报错
stripDelimiter解码时是否去掉分隔符
discarding如果没有找到分隔符且读取的数据超过最大长度,我们将将其设置为true
discardedBytes从源码上分析它,见下

   1.3 核心代码

 protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception 
	    //先找到结束符索引
        final int eol = findEndOfLine(buffer);
        if (!discarding) 
        	 //discarding默认为false,第一次必走这
            if (eol >= 0) 
                final ByteBuf frame;
                final int length = eol - buffer.readerIndex();
                final int delimLength = buffer.getByte(eol) == '\\r'? 2 : 1;
                //
                if (length > maxLength) 
                    buffer.readerIndex(eol + delimLength);
                    fail(ctx, length);
                    return null;
                

                if (stripDelimiter) 
                    frame = buffer.readRetainedSlice(length);
                    buffer.skipBytes(delimLength);
                 else 
                    frame = buffer.readRetainedSlice(length + delimLength);
                

                return frame;
             else 
            	//没有找到结束符索引,通过ByteBuf.readableBytes()方法获取当前消息的长度
                final int length = buffer.readableBytes();
                //如果长度超过最大长度
                if (length > maxLength) 
                   //使用discardedBytes临时存储消息的长度,并将discarding设置为true
                    discardedBytes = length;
                    buffer.readerIndex(buffer.writerIndex());
                    discarding = true;
                    if (failFast) 
                        fail(ctx, "over " + discardedBytes);
                    
                
                return null;
            
         else 
            if (eol >= 0) 
                final int length = discardedBytes + eol - buffer.readerIndex();
                final int delimLength = buffer.getByte(eol) == '\\r'? 2 : 1;
                buffer.readerIndex(eol + delimLength);
                discardedBytes = 0;
                discarding = false;
                if (!failFast) 
                    fail(ctx, length);
                
             else 
                discardedBytes += buffer.readableBytes();
                buffer.readerIndex(buffer.writerIndex());
            
            return null;
        
    

   1.4 使用效果

解码前:
+------------------------------------------------------------------+
                        接收到的数据报
“ Hello Netty.\\r\\n Are you ok?”
+------------------------------------------------------------------+
解码后:
+------------------------------------------------------------------+
                        解码之后的文本消息
“Hello Netty.”
+------------------------------------------------------------------+

作者: 小毛驴,一个游戏人 
梦想:世界和平   
原文地址: http://blog.csdn.net/liulongling 若有错误之处,请多多谅解并欢迎批评指正。

以上是关于Netty4.xNetty源码分析之LineBasedFrameDecoder的主要内容,如果未能解决你的问题,请参考以下文章

Netty4.XNetty源码分析之NioEventLoopGroup

Netty4.XNetty源码分析之ByteBuf

Netty4.xNetty TCP粘包/拆包问题的解决办法

Redux源码分析之compose

Zookeeper源码分析目录

Spark 源码分析系列