美文网首页
DelimiterBasedFrameDecoder

DelimiterBasedFrameDecoder

作者: Pillar_Zhong | 来源:发表于2019-08-01 21:29 被阅读0次

概要


A decoder that splits the received {@link ByteBuf}s by one or more
delimiters.  It is particularly useful for decoding the frames which ends
with a delimiter such as {@link Delimiters#nulDelimiter() NUL} or
{@linkplain Delimiters#lineDelimiter() newline characters}.

<h3>Predefined delimiters</h3>
<p>
{@link Delimiters} defines frequently used delimiters for convenience' sake.

<h3>Specifying more than one delimiter</h3>
<p>
{@link DelimiterBasedFrameDecoder} allows you to specify more than one
delimiter.  If more than one delimiter is found in the buffer, it chooses
the delimiter which produces the shortest frame.  For example, if you have
the following data in the buffer:
<pre>
+--------------+
| ABC\nDEF\r\n |
+--------------+
</pre>
a {@link DelimiterBasedFrameDecoder}({@link Delimiters#lineDelimiter() Delimiters.lineDelimiter()})
will choose {@code '\n'} as the first delimiter and produce two frames:
<pre>
+-----+-----+
| ABC | DEF |
+-----+-----+
</pre>
rather than incorrectly choosing {@code '\r\n'} as the first delimiter:
<pre>
+----------+
| ABC\nDEF |
+----------+
</pre>

关键属性

// 分隔符集合
private final ByteBuf[] delimiters;
// 最大消息长度
private final int maxFrameLength;
// 是否跳过分隔符
private final boolean stripDelimiter;
// 是否快速失败
private final boolean failFast;
// 丢弃模式
private boolean discardingTooLongFrame;
// 本次丢弃的长度
private int tooLongFrameLength;
// 行解码器
private final LineBasedFrameDecoder lineBasedDecoder;

解码

protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
    // 如果是基于换行符进行分割, 那么交给lineBasedDecoder处理
    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;
    // 这里主要是针对,读取的数据中有多个分隔符,用哪个来分隔的逻辑
    // 这里是取离readerindex最近的一个.
    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;
            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 = buffer.readRetainedSlice(minFrameLength);
            buffer.skipBytes(minDelimLength);
        } else {
            frame = buffer.readRetainedSlice(minFrameLength + minDelimLength);
        }

        return frame;
    // 如果找不到分隔符
    } else {
        // 如果是非丢弃模式, 那么readerindex直接跳到writerindex,表示争端数据全部丢弃 
        if (!discardingTooLongFrame) {
            if (buffer.readableBytes() > maxFrameLength) {
                // 因为还没有看到这一段的结束符, 那么进入丢弃模式
                tooLongFrameLength = buffer.readableBytes();
                buffer.skipBytes(buffer.readableBytes());
                discardingTooLongFrame = true;
                if (failFast) {
                    fail(tooLongFrameLength);
                }
            }
        } else {
            // 如果是丢弃模式, 那么继续丢弃, 直到看到结束符           
            tooLongFrameLength += buffer.readableBytes();
            buffer.skipBytes(buffer.readableBytes());
        }
        return null;
    }
}

相关文章

网友评论

      本文标题:DelimiterBasedFrameDecoder

      本文链接:https://www.haomeiwen.com/subject/lzkhdctx.html