Netty-源碼分析DelimiterBasedFrameDecoder

DelimiterBasedFrameDecoder自定義分隔符解碼器

 


package io.netty.handler.codec;

import static io.netty.util.internal.ObjectUtil.checkPositive;

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

import java.util.List;


//自定義分隔符解碼器
public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {

	//自定義的分隔符,可以使用多個
    private final ByteBuf[] delimiters;

    //每個消息段落最大長度
    private final int maxFrameLength;

    //解碼消息時,是否丟棄分隔符
    private final boolean stripDelimiter;

    //遇到錯誤時,是否拋出異常
    private final boolean failFast;

    //狀態變量-是否正在丟棄一個段的消息
    private boolean discardingTooLongFrame;

    //丟棄總長度
    private int tooLongFrameLength;

    //\r\n的解碼器
    private final LineBasedFrameDecoder lineBasedDecoder;

    
    public DelimiterBasedFrameDecoder(
            int maxFrameLength, boolean stripDelimiter, boolean failFast, ByteBuf... delimiters) {
        validateMaxFrameLength(maxFrameLength);
        if (delimiters == null) {
            throw new NullPointerException("delimiters");
        }
        if (delimiters.length == 0) {
            throw new IllegalArgumentException("empty delimiters");
        }

        //delimiters裏的分隔符 是否是\r\n
        if (isLineBased(delimiters) && !isSubclass()) {
            lineBasedDecoder = new LineBasedFrameDecoder(maxFrameLength, stripDelimiter, failFast);
            this.delimiters = null;
        } else {
        	//創建數組
            this.delimiters = new ByteBuf[delimiters.length];
            for (int i = 0; i < delimiters.length; i ++) {
                ByteBuf d = delimiters[i];
                validateDelimiter(d);
                //創建d的分區放入數組
                this.delimiters[i] = d.slice(d.readerIndex(), d.readableBytes());
            }
            lineBasedDecoder = null;
        }
        this.maxFrameLength = maxFrameLength;
        this.stripDelimiter = stripDelimiter;
        this.failFast = failFast;
    }

    //判斷是否是Delimiters.lineDelimiter()
    /** Returns true if the delimiters are "\n" and "\r\n".  */
    private static boolean isLineBased(final ByteBuf[] delimiters) {
        if (delimiters.length != 2) {
            return false;
        }
        ByteBuf a = delimiters[0];
        ByteBuf b = delimiters[1];
        if (a.capacity() < b.capacity()) {
            a = delimiters[1];
            b = delimiters[0];
        }
        return a.capacity() == 2 && b.capacity() == 1
                && a.getByte(0) == '\r' && a.getByte(1) == '\n'
                && b.getByte(0) == '\n';
    }

    //判斷是否是子類
    private boolean isSubclass() {
        return getClass() != DelimiterBasedFrameDecoder.class;
    }

    @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);
        }
    }

    
    protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
    	//如果分隔符是\r\n則用lineBasedDecoder解碼器解析
    	//此類就相當於lineBasedDecoder
        if (lineBasedDecoder != null) {
            return lineBasedDecoder.decode(ctx, buffer);
        }

        int minFrameLength = Integer.MAX_VALUE;
        ByteBuf minDelim = null;

        //循環所有分隔符,挨個去匹配
        for (ByteBuf delim: delimiters) {
        	//匹配分隔符的起始位置
            int frameLength = indexOf(buffer, delim);

            //大於0,並且小於int最大值 說明匹配成功
            if (frameLength >= 0 && frameLength < minFrameLength) {
                minFrameLength = frameLength;
                minDelim = delim;
            }
        }

        //說明匹配成功
        if (minDelim != null) {
        	//分隔符的capacity就代表了分隔符的長度
            int minDelimLength = minDelim.capacity();
            ByteBuf frame;

            //如果之前已經開始丟棄字節
            if (discardingTooLongFrame) {
                // We've just finished discarding a very large frame.
                // Go back to the initial state.
                //恢復標記位
                discardingTooLongFrame = false;
                //跳過minFrameLength+分隔符的長度,表示丟棄了前一個完整的消息
                buffer.skipBytes(minFrameLength + minDelimLength);

                //丟棄的字節總數
                int tooLongFrameLength = this.tooLongFrameLength;
                this.tooLongFrameLength = 0;
                if (!failFast) {
                    fail(tooLongFrameLength);
                }
                return null;
            }

            //消息長度大於閾值
            if (minFrameLength > maxFrameLength) {
                // Discard read frame.
                //丟棄一個消息
                buffer.skipBytes(minFrameLength + minDelimLength);
                fail(minFrameLength);
                return null;
            }

            //丟棄分隔符
            if (stripDelimiter) {
            	//返回一個消息frame
                frame = buffer.readRetainedSlice(minFrameLength);
                //丟棄分隔符
                buffer.skipBytes(minDelimLength);
            } else {
            	//返回一個消息,包括了分隔符
                frame = buffer.readRetainedSlice(minFrameLength + minDelimLength);
            }

            return frame;
        } else { //沒找到分隔符的位置

        	//正常情況
            if (!discardingTooLongFrame) {
            	//如果可讀字節大於最大長度限制
                if (buffer.readableBytes() > maxFrameLength) {
                    // Discard the content of the buffer until a delimiter is found.

                    tooLongFrameLength = buffer.readableBytes();
                    //丟棄字節
                    buffer.skipBytes(buffer.readableBytes());
                    //標記丟棄狀態
                    discardingTooLongFrame = true;
                    if (failFast) {
                        fail(tooLongFrameLength);
                    }
                }
            } else {
            	//之前discardingTooLongFrame已經設置爲true
                // Still discarding the buffer since a delimiter is not found.
                //增加總丟棄數量
                tooLongFrameLength += buffer.readableBytes();
                //繼續丟棄字節
                buffer.skipBytes(buffer.readableBytes());
            }
            return null;
        }
    }

    private void fail(long frameLength) {
        if (frameLength > 0) {
            throw new TooLongFrameException(
                            "frame length exceeds " + maxFrameLength +
                            ": " + frameLength + " - discarded");
        } else {
            throw new TooLongFrameException(
                            "frame length exceeds " + maxFrameLength +
                            " - discarding");
        }
    }

    
    private static int indexOf(ByteBuf haystack, ByteBuf needle) {
    	//循環輸入的字節流緩衝區,假設  a b c d e
        for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i ++) {
        	//從[a] 0位置開始找
            int haystackIndex = i;

            int needleIndex;
            //循環分隔符
            for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex ++) {
            	//如果分隔符與haystack.getByte(haystackIndex)不同,則結束當前循環
            	//haystack.getByte(haystackIndex) 從b開始繼續查詢
                if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex)) {
                    break;
                } else {
                    haystackIndex ++;
                    //依次拿出bcde進行匹配,如果輸入緩衝區到達末尾,並且分隔符緩衝區還沒有到達末尾,說明匹配失敗
                    if (haystackIndex == haystack.writerIndex() &&
                        needleIndex != needle.capacity() - 1) {
                        return -1;
                    }
                }
            }

            //如果分隔符緩衝區達到末尾,還沒發生上面的情況,說明匹配到了
            if (needleIndex == needle.capacity()) {
                // Found the needle from the haystack!
                //i減去haystack.readerIndex()的位置就是分隔符的位置
                return i - haystack.readerIndex();
            }
        }
        return -1;
    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章