Netty-源码分析LineBasedFrameDecoder

LineBasedFrameDecoder源码分析


package io.netty.handler.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ByteProcessor;

import java.util.List;

//\r\n分割器,编码采用ASCII或者UTF-8,因为\r\n的ASCII,或UTF-8编码都是一致的。
//都是0D,0A,再0x7F[0111 1111]范围内,超过这个范围的码点采用DelimiterBasedFrameDecoder解码
public class LineBasedFrameDecoder extends ByteToMessageDecoder {

    //每段消息的最大长度
    private final int maxLength;

    //超过最大长度是否抛出异常
    /** Whether or not to throw an exception as soon as we exceed maxLength. */
    private final boolean failFast = false;

    //是否跳过分隔符
    private final boolean stripDelimiter = true;

    //true的话需要丢弃一部分字节,因为超过了每段消息的最大长度
    /** True if we're discarding input because we're already over maxLength.  */
    private boolean discarding;

    //丢弃字节的长度
    private int discardedBytes;

    //偏移量
    /** Last scan position. */
    private int offset;

    @Override
    protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        //如果解析出decoded就放入out集合,父类会fire给下一个handler
        Object decoded = decode(ctx, in);
        if (decoded != null) {
            out.add(decoded);
        }
    }

    
    protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
        //查询\r\n的位置 假设消息为 "abcedf\r\n"  整体length=8  那么eol=6 
        final int eol = findEndOfLine(buffer);

        //discarding=false 说明正常情况
        if (!discarding) {

            //查询到\r\n的位置
            if (eol >= 0) {

                final ByteBuf frame;
                //6-0 = 6 是消息的长度
                final int length = eol - buffer.readerIndex();

                //eol的位置 如果是\r则分隔符2个字节, 否则一个字节。
                final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;

                //如果消息长度 大于 每段消息的最大长度限制
                if (length > maxLength) {

                    //把缓冲区readerIndex设置为0,相当于丢弃了前面的字节数据。
                    buffer.readerIndex(eol + delimLength);
                    //fire异常其它handler
                    fail(ctx, length);
                    return null;
                }

                //正常情况

                //去掉分隔符
                if (stripDelimiter) {
                    //返回子缓冲区,原始缓冲区的readerIndex会往后递增length个位置
                    //frame.refCnt=1    原始缓冲区的refCnt=2
                    //frame=[abcdef]
                    frame = buffer.readRetainedSlice(length);
                    //原始缓冲区丢弃delimLength长度的字节(丢弃分隔符)
                    buffer.skipBytes(delimLength);
                } else {
                    //不丢弃分隔符,那么length需要在加上分隔符的长度 6+2=8
                    frame = buffer.readRetainedSlice(length + delimLength);
                }

                //返回子缓冲区
                return frame;
            } else {
                //没找到分隔符位置

                //可读字节长度
                final int length = buffer.readableBytes();

                //大于每段信息最大长度范围
                if (length > maxLength) {

                    //记录需要丢弃的字节数
                    discardedBytes = length;

                    //跳过length个字节
                    buffer.readerIndex(buffer.writerIndex());

                    //设置标记
                    discarding = true;
                    offset = 0;

                    //抛异常
                    if (failFast) {
                        fail(ctx, "over " + discardedBytes);
                    }
                }
                return null;
            }
        } else { //进到这里,说明之前发生过特殊情况,需要丢弃一个消息

            //找到了分隔符
            if (eol >= 0) {

                //discardedBytes是之前记录需要丢弃的字节数   [eol - buffer.readerIndex()]是分隔符前面的字节数
                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的值 然后继续丢弃字节
                discardedBytes += buffer.readableBytes();
                buffer.readerIndex(buffer.writerIndex());
                // We skip everything in the buffer, we need to set the offset to 0 again.
                offset = 0;
            }
            return null;
        }
    }

    //fire异常信息
    private void fail(final ChannelHandlerContext ctx, int length) {
        fail(ctx, String.valueOf(length));
    }
    private void fail(final ChannelHandlerContext ctx, String length) {
        ctx.fireExceptionCaught(
                new TooLongFrameException(
                        "frame length (" + length + ") exceeds the allowed maximum (" + maxLength + ')'));
    }

    
    private int findEndOfLine(final ByteBuf buffer) {
        //buffer缓冲区中可读字节数
        int totalLength = buffer.readableBytes();
        //从readerIndex+offset开始,到totalLength - offset截止,默认offset=0,查找\n的位置
        int i = buffer.forEachByte(buffer.readerIndex() + offset, totalLength - offset, ByteProcessor.FIND_LF);

        //找到
        if (i >= 0) {
            offset = 0;
            //看前一个字节是否是\r
            if (i > 0 && buffer.getByte(i - 1) == '\r') {
                //位置往前挪一位
                i--;
            }
        } else {
            //没找到- offset等于当前可读字节数
            offset = totalLength;
        }
        return i;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值