Netty源码分析(六) DelimiterBasedFrameDecoder

我们之前介绍了Netty的解码器ByteToMessageDecoder,那Netty具体的解码器有哪几种呢,Netty提供的解码器主要有以下几个:
  DelimiterBasedFrameDecoder 解决TCP的粘包解码器
  StringDecoder 消息转成String解码器
  LineBasedFrameDecoder 自动完成标识符分隔解码器
  FixedLengthFrameDecoder 固定长度解码器,二进制
  Base64Decoder base64 解码器
下面我们就来说说DelimiterBasedFrameDecoder这个类。
在此之前先说下tcp通信的问题, 当客户端向服务端发送了一个大的数据包时(如600M),TCP几乎不会一次把这个包完整的发送到服务端,TCP分把这个包分包,分几次发给服务端,至于TCP要分多少次,这是不可预测的。那怎么处理这种问题呢?这就需要用到我们介绍的DelimiterBasedFrameDecoder了。DelimiterBasedFrameDecoder是以换行符作为分割符,对数据进行解码。也就是\n和\r\n。好了,我们来看看decode方法是怎么实现的

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) {
            // We've just finished discarding a very large frame.
            // Go back to the initial state.
            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 {
        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 {
            // Still discarding the buffer since a delimiter is not found.
            tooLongFrameLength += buffer.readableBytes();
            buffer.skipBytes(buffer.readableBytes());
        }
        return null;
    }
}

简单的说,就是DelimiterBasedFrameDecoder有两种工作模式,丢弃模式和非丢弃模式。当在丢弃模式下,大于一个数据包的数据会被丢弃,直接skip对应的字节。在非丢弃模式下,则是存在容器里,然后等待下一个数据包到来的时候,拼接到一起。数据解析完成后,再把解码后的对象传递给下个节点。
DelimiterBasedFrameDecoder就分析到这里了。

你可能感兴趣的:(Netty源码分析(六) DelimiterBasedFrameDecoder)