Netty解碼

圖片.png

圖片.png

Q

  • 解碼器抽象解碼過程?
  • netty提供哪些拆箱即用的解碼器?解碼器基類與常見解碼器解析

一、ByteToMessageDecoder解碼步驟

  • **累加字節(jié)流
    設(shè)置first為cumulation是否為空,累加器為空表賦值為讀進(jìn)來的ByteBuf對象,累加器非空調(diào)用cumulator的cumulate()方法通過ByteBuffer的writeBytes()方法把當(dāng)前累加器里面的數(shù)據(jù)和讀進(jìn)來的數(shù)據(jù)進(jìn)行累加
  • 調(diào)用子類的decode方法進(jìn)行解析
    調(diào)用callDecode()方法將累加器數(shù)據(jù)解析到的對象放到CodecOutputList向下進(jìn)行傳播,循環(huán)判斷累加器里面是否有數(shù)據(jù),通過調(diào)用fireChannelRead()方法向下進(jìn)行事件傳播,調(diào)用decode()方法ByteBuf解碼根據(jù)不同協(xié)議子類的解碼器把當(dāng)前讀到的所有數(shù)據(jù)即累加器里面的數(shù)據(jù)取出二進(jìn)制數(shù)據(jù)流解析放進(jìn)CodecOutputList
  • 將解析到的ByteBuf向下傳播
    調(diào)用fireChannelRead()方法循環(huán)遍歷CodecOutputList通過事件傳播機(jī)制ctx.fireChannelRead()調(diào)用CodecOutputList的getUnsafe()方法獲取ByteBuf把解析到的ByteBuf對象向下進(jìn)行傳播

ByteToMessageDecoder.channelRead

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof ByteBuf) {//基于ByteBuf解碼
            CodecOutputList out = CodecOutputList.newInstance();
            try {
                ByteBuf data = (ByteBuf) msg;
                first = cumulation == null;
                if (first) {
                    cumulation = data;//初始化cumulation 
                } else {
                    cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data);//累加
                }
                callDecode(ctx, cumulation, out);//解析cumulation中ByteBuf到OutputList
            } catch (DecoderException e) {
                throw e;
            } catch (Throwable t) {
                throw new DecoderException(t);
            } finally {
                if (cumulation != null && !cumulation.isReadable()) {
                    numReads = 0;
                    cumulation.release();
                    cumulation = null;
                } else if (++ numReads >= discardAfterReads) {
                    // We did enough reads already try to discard some bytes so we not risk to see a OOME.
                    // See https://github.com/netty/netty/issues/4275
                    numReads = 0;
                    discardSomeReadBytes();
                }

                int size = out.size();
                decodeWasNull = !out.insertSinceRecycled();
                fireChannelRead(ctx, out, size);//解析出的數(shù)據(jù)outlist,向后傳播
                out.recycle();//outlist回收
            }
        } else {
            ctx.fireChannelRead(msg);
        }
    }

cumulator.cumulate

public static final Cumulator MERGE_CUMULATOR = new Cumulator() {
        @Override
        public ByteBuf cumulate(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf in) {
            final ByteBuf buffer;
            if (cumulation.writerIndex() > cumulation.maxCapacity() - in.readableBytes()
                    || cumulation.refCnt() > 1 || cumulation.isReadOnly()) {
                buffer = expandCumulation(alloc, cumulation, in.readableBytes());//cumulation擴(kuò)容
            } else {
                buffer = cumulation;
            }
            buffer.writeBytes(in);
            in.release();
            return buffer;
        }
    };

callDecode

protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        try {
            while (in.isReadable()) {//如果累加器還有數(shù)據(jù)
                int outSize = out.size();

                if (outSize > 0) {//如果outputlist有數(shù)據(jù),則向后傳播,并清空
                    fireChannelRead(ctx, out, outSize);
                    out.clear();

                    if (ctx.isRemoved()) {
                        break;
                    }
                    outSize = 0;
                }

                int oldInputLength = in.readableBytes();
                decodeRemovalReentryProtection(ctx, in, out);

                if (ctx.isRemoved()) {
                    break;
                }

                if (outSize == out.size()) {//說明size沒變化,沒解析到數(shù)據(jù)
                    if (oldInputLength == in.readableBytes()) {
                        break;
                    } else {
                        continue;
                    }
                }
                if (oldInputLength == in.readableBytes()) {
                    throw new DecoderException(
                            StringUtil.simpleClassName(getClass()) +
                                    ".decode() did not read anything but decoded a message.");
                }

                if (isSingleDecode()) {
                    break;
                }
            }
        } catch (DecoderException e) {
            throw e;
        } catch (Throwable cause) {
            throw new DecoderException(cause);
        }
    }

final void decodeRemovalReentryProtection(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
            throws Exception {
        decodeState = STATE_CALLING_CHILD_DECODE;
        try {
            decode(ctx, in, out);//抽象方法,子類實(shí)現(xiàn),解析后對象放在out里
        } finally {
            boolean removePending = decodeState == STATE_HANDLER_REMOVED_PENDING;
            decodeState = STATE_INIT;
            if (removePending) {
                handlerRemoved(ctx);
            }
        }
    }

二、基于固定長度解碼器分析FixedLengthFrameDecoder

基于固定長度解碼器FixedLengthFrameDecoder成員變量frameLength表示固定長度,解碼器以多少長度分割解析,構(gòu)造方法傳參frameLength賦值給frameLength保存。
調(diào)用decode()方法解析累加器數(shù)據(jù)添加到CodecOutputList,判斷累加器可讀字節(jié)是否小于frameLength,小于返回空表示沒有從累加器里面讀取數(shù)據(jù),反之調(diào)用readRetainedSlice()方法從當(dāng)前累加器里面截取frameLength長度ByteBuf,返回從當(dāng)前readerIndex開始增加frameLength長度的Buffer子區(qū)域新保留切片。

FixedLengthFrameDecoder

/**
 * A decoder that splits the received {@link ByteBuf}s by the fixed number
 * of bytes. For example, if you received the following four fragmented packets:
 * <pre>
 * +---+----+------+----+
 * | A | BC | DEFG | HI |
 * +---+----+------+----+
 * </pre>
 * A {@link FixedLengthFrameDecoder}{@code (3)} will decode them into the
 * following three packets with the fixed length:
 * 如果固定長度為3,上面數(shù)據(jù)包會被解析成如下:
 * <pre>
 * +-----+-----+-----+
 * | ABC | DEF | GHI |
 * +-----+-----+-----+
 * </pre>
 */
public class FixedLengthFrameDecoder extends ByteToMessageDecoder {

    private final int frameLength;

    public FixedLengthFrameDecoder(int frameLength) {
        if (frameLength <= 0) {
            throw new IllegalArgumentException(
                    "frameLength must be a positive integer: " + frameLength);
        }
        this.frameLength = frameLength;
    }

    @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(
            @SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        if (in.readableBytes() < frameLength) {//當(dāng)前可讀字節(jié)小于固定長度,返回null,不添加到outList
            return null;
        } else {
            return in.readRetainedSlice(frameLength);
        }
    }
}

三、行解碼器分析LineBasedFrameDecoder

基于行解碼器LineBasedFrameDecoder

  • 成員變量
    maxLength[行解碼器解析數(shù)據(jù)包最大長度],failFast[超越最大長度是否立即拋異常],
    stripDelimiter[解析數(shù)據(jù)包是否帶換行符,換行符支持\n和\r],
    discarding[解碼過程是否處于丟棄模式],
    discardedBytes[解碼過程丟棄字節(jié)],
  • 調(diào)用decode()方法解析累加器cumulation數(shù)據(jù)把數(shù)據(jù)包添加到CodecOutputList,通過findEndOfLine()方法從累加器ByteBuf里面查找獲取行的結(jié)尾eol即\n或者\(yùn)r\n,
  • 非丟棄模式查找到行的結(jié)尾eol計算從換行符到可讀字節(jié)的長度length和分隔符的長度判斷l(xiāng)ength是否大于解析數(shù)據(jù)包最大長度maxLength,大于maxLength則readerIndex指向行的結(jié)尾eol后面的可讀字節(jié)丟棄數(shù)據(jù)通過fail()方法傳播異常,判斷分隔符是否算在完整數(shù)據(jù)包范疇從buffer分割length長度獲取新保留切片并且buffer跳過分隔符readerIndex指向分隔符后面的可讀字節(jié),
  • 未查找到行的結(jié)尾eol獲取可讀字節(jié)長度length超過解析數(shù)據(jù)包最大長度maxLength賦值discardedBytes為length讀指針readerIndex指向?qū)懼羔榳riterIndex賦值discarding為true進(jìn)入丟棄模式并且根據(jù)failFast調(diào)用fail()方法立即傳播fail異常,
  • 丟棄模式查找到行的結(jié)尾eol按照丟棄字節(jié)+從換行符到可讀字節(jié)的長度計算length和換行符長度將readerIndex指向丟棄字節(jié)換行符后面的可讀字節(jié)賦值discardedBytes為0并且discarding為false表示當(dāng)前屬于非丟棄模式,根據(jù)failFast調(diào)用fail()方法立即傳播fail異常,
    未查找到行的結(jié)尾eol則discardedBytes增加buffer的可讀字節(jié)并且讀指針readerIndex指向?qū)懼羔榳riterIndex
圖片.png
public class LineBasedFrameDecoder extends ByteToMessageDecoder {

    /** 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;//解析的數(shù)據(jù)包時候帶換行符,false帶,true不帶

    /** True if we're discarding input because we're already over maxLength.  */
    private boolean discarding;//超過最大長度時候拋棄
    private int discardedBytes;//拋棄的字節(jié)數(shù)

    /**
     * Creates a new decoder.
     * @param maxLength  the maximum length of the decoded frame.
     *                   A {@link TooLongFrameException} is thrown if
     *                   the length of the frame exceeds this value.
     */
    public LineBasedFrameDecoder(final int maxLength) {
        this(maxLength, true, false);
    }

    /**
     * Creates a new decoder.
     * @param maxLength  the maximum length of the decoded frame.
     *                   A {@link TooLongFrameException} is thrown if
     *                   the length of the frame exceeds this value.
     * @param stripDelimiter  whether the decoded frame should strip out the
     *                        delimiter or not
     * @param failFast  If <tt>true</tt>, a {@link TooLongFrameException} is
     *                  thrown as soon as the decoder notices the length of the
     *                  frame will exceed <tt>maxFrameLength</tt> regardless of
     *                  whether the entire frame has been read.
     *                  If <tt>false</tt>, a {@link TooLongFrameException} is
     *                  thrown after the entire frame that exceeds
     *                  <tt>maxFrameLength</tt> has been read.
     */
    public LineBasedFrameDecoder(final int maxLength, final boolean stripDelimiter, final boolean failFast) {
        this.maxLength = maxLength;
        this.failFast = failFast;
        this.stripDelimiter = stripDelimiter;
    }

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

    /**
     * Create a frame out of the {@link ByteBuf} and return it.
     *
     * @param   ctx             the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to
     * @param   buffer          the {@link ByteBuf} from which to read data
     * @return  frame           the {@link ByteBuf} which represent the frame or {@code null} if no frame could
     *                          be created.
     */
    protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
        final int eol = findEndOfLine(buffer);//尋找行的結(jié)尾,\n或者\(yùn)r\n
        if (!discarding) {//非丟棄模式
            if (eol >= 0) {
                final ByteBuf frame;
                final int length = eol - buffer.readerIndex();//endofline-readerIndex即為可讀字節(jié)
                final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;//分隔符長度,2或者1

                if (length > maxLength) {
                    buffer.readerIndex(eol + delimLength);//當(dāng)可讀字節(jié)大于行最大長度,則移動readerIndex到下一個可讀區(qū)域
                    fail(ctx, length);//傳播異常
                    return null;//返回null表示當(dāng)前什么也沒有解析
                }

                if (stripDelimiter) {//是否跳過分隔符
                    frame = buffer.readRetainedSlice(length);//解析數(shù)據(jù)不包含分隔符
                    buffer.skipBytes(delimLength);
                } else {
                    frame = buffer.readRetainedSlice(length + delimLength);//解析數(shù)據(jù)包含分隔符
                }

                return frame;//返回解析數(shù)據(jù)包
            } else {//readerIndex和writerIndex沒有換行符
                final int length = buffer.readableBytes();
                if (length > maxLength) {//可讀長度大于最大行長度
                    discardedBytes = length;//丟棄字節(jié)長度
                    buffer.readerIndex(buffer.writerIndex());//讀指針直接移到寫指針
                    discarding = true;//進(jìn)入丟棄模式
                    if (failFast) {//是否快速失敗,傳播異常
                        fail(ctx, "over " + discardedBytes);
                    }
                }
                return null;
            }
        } else {//丟棄模式
            if (eol >= 0) {
                final int length = discardedBytes + eol - buffer.readerIndex();//丟棄長度=discardedBytes +當(dāng)前可讀長度
                final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
                buffer.readerIndex(eol + delimLength);//移動指針到分隔符之后
                discardedBytes = 0;//重置丟棄長度
                discarding = false;//進(jìn)入非丟棄模式
                if (!failFast) {
                    fail(ctx, length);
                }
            } else {//沒有找到分隔符,直接移動readerIndex到writerIndex
                discardedBytes += buffer.readableBytes();
                buffer.readerIndex(buffer.writerIndex());
            }
            return null;
        }
    }

    private void fail(final ChannelHandlerContext ctx, int length) {
        fail(ctx, String.valueOf(length));
    }

四、分隔符解碼器DelimiterBasedFrameDecoder

圖片.png
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;
    /** Set only when decoding with "\n" and "\r\n" as the delimiter.  */
    private final LineBasedFrameDecoder lineBasedDecoder;


    public DelimiterBasedFrameDecoder(int maxFrameLength, ByteBuf delimiter) {
        this(maxFrameLength, true, delimiter);
    }


    public DelimiterBasedFrameDecoder(
            int maxFrameLength, boolean stripDelimiter, ByteBuf delimiter) {
        this(maxFrameLength, stripDelimiter, true, delimiter);
    }


    public DelimiterBasedFrameDecoder(
            int maxFrameLength, boolean stripDelimiter, boolean failFast,
            ByteBuf delimiter) {
        this(maxFrameLength, stripDelimiter, failFast, new ByteBuf[] {
                delimiter.slice(delimiter.readerIndex(), delimiter.readableBytes())});
    }


    public DelimiterBasedFrameDecoder(int maxFrameLength, ByteBuf... delimiters) {
        this(maxFrameLength, true, delimiters);
    }


    public DelimiterBasedFrameDecoder(
            int maxFrameLength, boolean stripDelimiter, ByteBuf... delimiters) {
        this(maxFrameLength, stripDelimiter, true, delimiters);
    }

    //構(gòu)造方法
    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");
        }

        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);
                this.delimiters[i] = d.slice(d.readerIndex(), d.readableBytes());
            }
            lineBasedDecoder = null;
        }
        this.maxFrameLength = maxFrameLength;
        this.stripDelimiter = stripDelimiter;
        this.failFast = failFast;
    }

    /**判斷分隔符是否是 "\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';
    }

    @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 {
        if (lineBasedDecoder != null) {//行解碼器不為空,則使用 行解碼器解碼
            return lineBasedDecoder.decode(ctx, buffer);
        }
        // Try all delimiters and choose the delimiter which yields the shortest frame.
        int minFrameLength = Integer.MAX_VALUE;
        ByteBuf minDelim = null;
        for (ByteBuf delim: delimiters) {//找到最小分隔符
            int frameLength = indexOf(buffer, delim);
            if (frameLength >= 0 && frameLength < minFrameLength) {
                minFrameLength = frameLength;
                minDelim = delim;
            }
        }

        if (minDelim != null) {//找到分隔符
            int minDelimLength = minDelim.capacity();
            ByteBuf frame;

            if (discardingTooLongFrame) {//是否丟棄模式
                discardingTooLongFrame = false;//重置丟棄模式為false
                buffer.skipBytes(minFrameLength + minDelimLength);//跳過

                int tooLongFrameLength = this.tooLongFrameLength;
                this.tooLongFrameLength = 0;
                if (!failFast) {//是否已快速失敗
                    fail(tooLongFrameLength);
                }
                return null;
            }

           //最小分隔符分割的數(shù)據(jù)包仍大于最大數(shù)據(jù)包
            if (minFrameLength > maxFrameLength) {
                // Discard read frame.
                buffer.skipBytes(minFrameLength + minDelimLength);//跳過
                fail(minFrameLength);//傳播異常
                return null;
            }

            if (stripDelimiter) {//是否包含分隔符
                frame = buffer.readRetainedSlice(minFrameLength);
                buffer.skipBytes(minDelimLength);
            } else {
                frame = buffer.readRetainedSlice(minFrameLength + minDelimLength);
            }

            return frame;
        } else {//沒有找到分隔符時
            if (!discardingTooLongFrame) {//非丟棄狀態(tài)
                if (buffer.readableBytes() > maxFrameLength) {//可讀數(shù)據(jù)大于允許最大數(shù)據(jù)包
                    // Discard the content of the buffer until a delimiter is found.
                    tooLongFrameLength = buffer.readableBytes();
                    buffer.skipBytes(buffer.readableBytes());//直接跳過可讀數(shù)據(jù)
                    discardingTooLongFrame = true;//進(jìn)去丟棄狀態(tài)
                    if (failFast) {//是否快速失敗
                        fail(tooLongFrameLength);
                    }
                }
            } else {//丟棄狀態(tài)
                // Still discarding the buffer since a delimiter is not found.
                tooLongFrameLength += buffer.readableBytes();//記錄丟棄的字節(jié)數(shù)
                buffer.skipBytes(buffer.readableBytes());//直接跳過可讀數(shù)據(jù)
            }
            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");
        }
    }

    /**
     * Returns the number of bytes between the readerIndex of the haystack and
     * the first needle found in the haystack.  -1 is returned if no needle is
     * found in the haystack.
     */
    private static int indexOf(ByteBuf haystack, ByteBuf needle) {
        for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i ++) {
            int haystackIndex = i;
            int needleIndex;
            for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex ++) {
                if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex)) {
                    break;
                } else {
                    haystackIndex ++;
                    if (haystackIndex == haystack.writerIndex() &&
                        needleIndex != needle.capacity() - 1) {
                        return -1;
                    }
                }
            }

            if (needleIndex == needle.capacity()) {
                // Found the needle from the haystack!
                return i - haystack.readerIndex();
            }
        }
        return -1;
    }

    private static void validateDelimiter(ByteBuf delimiter) {
        if (delimiter == null) {
            throw new NullPointerException("delimiter");
        }
        if (!delimiter.isReadable()) {
            throw new IllegalArgumentException("empty delimiter");
        }
    }

    private static void validateMaxFrameLength(int maxFrameLength) {
        if (maxFrameLength <= 0) {
            throw new IllegalArgumentException(
                    "maxFrameLength must be a positive integer: " +
                    maxFrameLength);
        }
    }
}

五、基于長度域解碼器LengthFieldBasedFrameDecoder

1、成員變量解析

  • lengthFieldOffset:長度域偏移量即長度域在二進(jìn)制數(shù)據(jù)流里面偏移量
  • lengthFieldLength:長度域長度即從長度域開始往后幾個字節(jié)組合起來表示長度
  • lengthAdjustment:長度域表示長度+額外調(diào)整長度=數(shù)據(jù)包長度,即長度域計算完整數(shù)據(jù)包長度,長度額外調(diào)整
  • initialBytesToStrip:decode出完整數(shù)據(jù)包之后向下傳播的時候是否需要砍掉幾個字節(jié)即解析數(shù)據(jù)包前面跳過字節(jié)
    構(gòu)造函數(shù)
public LengthFieldBasedFrameDecoder(
            ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength,
            int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
        if (byteOrder == null) {
            throw new NullPointerException("byteOrder");
        }

        if (maxFrameLength <= 0) {
            throw new IllegalArgumentException(
                    "maxFrameLength must be a positive integer: " +
                    maxFrameLength);
        }

        if (lengthFieldOffset < 0) {
            throw new IllegalArgumentException(
                    "lengthFieldOffset must be a non-negative integer: " +
                    lengthFieldOffset);
        }

        if (initialBytesToStrip < 0) {
            throw new IllegalArgumentException(
                    "initialBytesToStrip must be a non-negative integer: " +
                    initialBytesToStrip);
        }

        if (lengthFieldOffset > maxFrameLength - lengthFieldLength) {
            throw new IllegalArgumentException(
                    "maxFrameLength (" + maxFrameLength + ") " +
                    "must be equal to or greater than " +
                    "lengthFieldOffset (" + lengthFieldOffset + ") + " +
                    "lengthFieldLength (" + lengthFieldLength + ").");
        }

        this.byteOrder = byteOrder;
        this.maxFrameLength = maxFrameLength;
        this.lengthFieldOffset = lengthFieldOffset;
        this.lengthFieldLength = lengthFieldLength;
        this.lengthAdjustment = lengthAdjustment;
        lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength;
        this.initialBytesToStrip = initialBytesToStrip;
        this.failFast = failFast;
    }

示例1

 * <b>lengthFieldOffset</b>   = <b>0</b>
 * <b>lengthFieldLength</b>   = <b>2</b>
 * lengthAdjustment    = 0
 * initialBytesToStrip = 0 (= do not strip header)
 * BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
 * +--------+----------------+      +--------+----------------+
 * | Length | Actual Content |----->| Length | Actual Content |
 * | 0x000C | "HELLO, WORLD" |      | 0x000C | "HELLO, WORLD" |
 * +--------+----------------+      +--------+----------------+

new LengthFieldBasedFrameDecoder(Integer.MAX, 0, 2);
1.第一個參數(shù)是 maxFrameLength 表示的是包的最大長度,超出包的最大長度netty將會做一些特殊處理,后面會講到
2.第二個參數(shù)指的是長度域的偏移量lengthFieldOffset,在這里是0,表示無偏移
3.第三個參數(shù)指的是長度域長度lengthFieldLength,這里是2,表示長度域的長度為2

示例2

 * lengthFieldOffset   = 0
 * lengthFieldLength   = 2
 * lengthAdjustment    = 0
 * <b>initialBytesToStrip</b> = <b>2</b> (= the length of the Length field)
 * BEFORE DECODE (14 bytes)         AFTER DECODE (12 bytes)
 * +--------+----------------+      +----------------+
 * | Length | Actual Content |----->| Actual Content |
 * | 0x000C | "HELLO, WORLD" |      | "HELLO, WORLD" |
 * +--------+----------------+      +----------------+

new LengthFieldBasedFrameDecoder(Integer.MAX, 0, 2, 0, 2);
前面三個參數(shù)的含義和上文相同
第四個參數(shù)lengthAdjustment,后面再講
第五個參數(shù)就是initialBytesToStrip,這里為2,表示獲取完一個完整的數(shù)據(jù)包之后,忽略前面的2個字節(jié)(長度)

示例3

 * lengthFieldOffset   =  0
 * lengthFieldLength   =  2
 * <b>lengthAdjustment</b>    = <b>-2</b> (= the length of the Length field)
 * initialBytesToStrip =  0
 *
 * BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
 * +--------+----------------+      +--------+----------------+
 * | Length | Actual Content |----->| Length | Actual Content |
 * | 0x000E | "HELLO, WORLD" |      | 0x000E | "HELLO, WORLD" |
 * +--------+----------------+      +--------+----------------+

new LengthFieldBasedFrameDecoder(Integer.MAX, 0, 2,-2,0);
lengthFieldLength 是2,lengthAdjustment為-2,表示數(shù)據(jù)包長度0x000E-2,即為0x000C

示例4

 * <b>lengthFieldOffset</b>   = <b>2</b> (= the length of Header 1)
 * <b>lengthFieldLength</b>   = <b>3</b>
 * lengthAdjustment    = 0
 * initialBytesToStrip = 0
 *
 * BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)
 * +----------+----------+----------------+      +----------+----------+----------------+
 * | Header 1 |  Length  | Actual Content |----->| Header 1 |  Length  | Actual Content |
 * |  0xCAFE  | 0x00000C | "HELLO, WORLD" |      |  0xCAFE  | 0x00000C | "HELLO, WORLD" |
 * +----------+----------+----------------+      +----------+----------+----------------+

new LengthFieldBasedFrameDecoder(Integer.MAX, 2, 3, 0, 0);
長度域偏移為2,長度域大小為3,即0x00000C

示例5

 * lengthFieldOffset   = 0
 * lengthFieldLength   = 3
 * <b>lengthAdjustment</b>    = <b>2</b> (= the length of Header 1)
 * initialBytesToStrip = 0
 *
 * BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)
 * +----------+----------+----------------+      +----------+----------+----------------+
 * |  Length  | Header 1 | Actual Content |----->|  Length  | Header 1 | Actual Content |
 * | 0x00000C |  0xCAFE  | "HELLO, WORLD" |      | 0x00000C |  0xCAFE  | "HELLO, WORLD" |
 * +----------+----------+----------------+      +----------+----------+----------------+

new LengthFieldBasedFrameDecoder(Integer.MAX, 0, 3, 2, 0);
長度域中0x00000C ,Header 占用2字節(jié),所以數(shù)據(jù)包長度為0x00000C +2(lengthAdjustment)

示例6

 * lengthFieldOffset   = 1 (= the length of HDR1)
 * lengthFieldLength   = 2
 * <b>lengthAdjustment</b>    = <b>1</b> (= the length of HDR2)
 * <b>initialBytesToStrip</b> = <b>3</b> (= the length of HDR1 + LEN)
 *
 * BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
 * +------+--------+------+----------------+      +------+----------------+
 * | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
 * | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
 * +------+--------+------+----------------+      +------+----------------+
new LengthFieldBasedFrameDecoder(Integer.MAX, 1, 2, 1, 3);
數(shù)據(jù)包長度為0x000C  +1(lengthAdjustment),截取前面3(initialBytesToStrip)個字節(jié)

示例7

 * lengthFieldOffset   =  1
 * lengthFieldLength   =  2
 * <b>lengthAdjustment</b>    = <b>-3</b> (= the length of HDR1 + LEN, negative)
 * <b>initialBytesToStrip</b> = <b> 3</b>
 *
 * BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
 * +------+--------+------+----------------+      +------+----------------+
 * | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
 * | 0xCA | 0x0010 | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
 * +------+--------+------+----------------+      +------+----------------+

2、decode方法分析

  • 計算需要抽取的數(shù)據(jù)包長度。
  • 跳過字節(jié)邏輯處理。
  • 丟棄模式下的處理。
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        if (discardingTooLongFrame) {//先判斷是否丟棄模式,進(jìn)行丟棄處理
            long bytesToDiscard = this.bytesToDiscard;//待丟棄的字節(jié)數(shù)
            int localBytesToDiscard = (int) Math.min(bytesToDiscard, in.readableBytes());//
            in.skipBytes(localBytesToDiscard);
            bytesToDiscard -= localBytesToDiscard;//待丟棄的字節(jié)數(shù)減去本次已丟棄,即下次需丟棄的字節(jié)數(shù)
            this.bytesToDiscard = bytesToDiscard;

            failIfNecessary(false);
        }
        //如果當(dāng)前可讀字節(jié)數(shù)還未到達(dá)長度域結(jié)尾,則不足以解析數(shù)據(jù)包
        if (in.readableBytes() < lengthFieldEndOffset) {
            return null;
        }

        int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset;//長度域絕對位置
        long frameLength = getUnadjustedFrameLength(in, actualLengthFieldOffset, lengthFieldLength, byteOrder);//抽取的數(shù)據(jù)包長度

        if (frameLength < 0) {
            in.skipBytes(lengthFieldEndOffset);
            throw new CorruptedFrameException(
                    "negative pre-adjustment length field: " + frameLength);
        }

        frameLength += lengthAdjustment + lengthFieldEndOffset;//實(shí)際抽取的數(shù)據(jù)包長度

        if (frameLength < lengthFieldEndOffset) {
            in.skipBytes(lengthFieldEndOffset);
            throw new CorruptedFrameException(
                    "Adjusted frame length (" + frameLength + ") is less " +
                    "than lengthFieldEndOffset: " + lengthFieldEndOffset);
        }

        if (frameLength > maxFrameLength) {//數(shù)據(jù)包長度大于maxFrameLength,進(jìn)去丟棄模式
            long discard = frameLength - in.readableBytes();
            tooLongFrameLength = frameLength;

            if (discard < 0) {
                // buffer contains more bytes then the frameLength so we can discard all now
                in.skipBytes((int) frameLength);//直接丟棄frameLength長度的數(shù)據(jù)包
            } else {
                // Enter the discard mode and discard everything received so far.
                discardingTooLongFrame = true;//丟棄模式
                bytesToDiscard = discard;//還需要丟棄字節(jié)數(shù)
                in.skipBytes(in.readableBytes());
            }
            failIfNecessary(true);//
            return null;
        }

        // never overflows because it's less than maxFrameLength
        int frameLengthInt = (int) frameLength;
        if (in.readableBytes() < frameLengthInt) {//可讀數(shù)據(jù)小于實(shí)際抽取的數(shù)據(jù)包長度,即不完整數(shù)據(jù)包
            return null;
        }

        if (initialBytesToStrip > frameLengthInt) {
            in.skipBytes(frameLengthInt);
            throw new CorruptedFrameException(
                    "Adjusted frame length (" + frameLength + ") is less " +
                    "than initialBytesToStrip: " + initialBytesToStrip);
        }
        in.skipBytes(initialBytesToStrip);//跳過字節(jié)數(shù)

        // extract frame
        int readerIndex = in.readerIndex();//讀指針
        int actualFrameLength = frameLengthInt - initialBytesToStrip;//實(shí)際數(shù)據(jù)包
        ByteBuf frame = extractFrame(ctx, in, readerIndex, actualFrameLength);
        in.readerIndex(readerIndex + actualFrameLength);
        return frame;
    }

//支持1、2、3、4、8的length
protected long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) {
        buf = buf.order(order);
        long frameLength;
        switch (length) {
        case 1:
            frameLength = buf.getUnsignedByte(offset);
            break;
        case 2:
            frameLength = buf.getUnsignedShort(offset);
            break;
        case 3:
            frameLength = buf.getUnsignedMedium(offset);
            break;
        case 4:
            frameLength = buf.getUnsignedInt(offset);
            break;
        case 8:
            frameLength = buf.getLong(offset);
            break;
        default:
            throw new DecoderException(
                    "unsupported lengthFieldLength: " + lengthFieldLength + " (expected: 1, 2, 3, 4, or 8)");
        }
        return frameLength;
    }

protected ByteBuf extractFrame(ChannelHandlerContext ctx, ByteBuf buffer, int index, int length) {
        return buffer.retainedSlice(index, length);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容