netty4源码解析

netty-LengthFieldBasedFrameDecoder源码解析

package io.netty.heandler.codec;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.CorruptedFrameException;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.util.internal.ObjectUtil;

import java.nio.ByteOrder;
import java.util.List;

/**
 * 源码解析
 *
 * @ClassName: LengthFieldBasedFrameDecoder
 * @author: LangXing
 * @date: 2019-12-24 14:59
 * @Version 1.0
 */
public class LengthFieldBasedFrameDecoder {

	private final ByteOrder byteOrder;
	/**
	 * 最大长度
	 */
	private final int maxFrameLength;
	/**
	 * 偏移量(长度字段的偏移多少个字节)
	 */
	private final int lengthFieldOffset;
	/**
	 * 定义多少个字节是长度字段
	 */
	private final int lengthFieldLength;
	/**
	 * 偏移量字段+长度字段
	 */
	private final int lengthFieldEndOffset;
	/**
	 * 修改帧数据长度字段中定义的值,可以为负数 因为有时候我们习惯把头部记入长度,若为负数,则说明要推后多少个字段
	 */
	private final int lengthAdjustment;
	/**
	 * 解析时候跳过多少个长度
	 */
	private final int initialBytesToStrip;
	/**
	 * 快速失败
	 * 为true,当frame长度超过maxFrameLength时立即报TooLongFrameException异常
	 * 为false,读取完整个帧再报异
	 */
	private final boolean failFast;
	/**
	 * 是否开启忽略过长的字节
	 */
	private boolean discardingTooLongFrame;
	/**
	 * 计算出来的长度
	 */
	private long tooLongFrameLength;
	/**
	 * 字节抛弃长度
	 */
	private long bytesToDiscard;

	/**
	 * 定义最大字节,偏移量,长度字节
	 *
	 * @param maxFrameLength    最大字节
	 * @param lengthFieldOffset 偏移量(单位:字节)
	 * @param lengthFieldLength 长度字节
	 */
	public LengthFieldBasedFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) {
		this(maxFrameLength, lengthFieldOffset, lengthFieldLength, 0, 0);
	}

	/**
	 * 定义最大字节,偏移量,长度字节
	 *
	 * @param maxFrameLength      最大字节
	 * @param lengthFieldOffset   偏移量(单位:字节)
	 * @param lengthFieldLength   长度字节
	 * @param lengthAdjustment    修改帧数据长度字段中定义的值,可以为负数 因为有时候我们习惯把头部记入长度,若为负数,则说明要推后多少个字段
	 * @param initialBytesToStrip 设置返回字节从哪个位置开始
	 */
	public LengthFieldBasedFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
		this(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, true);
	}

	/**
	 *
	 * @param maxFrameLength 最大字节
	 * @param lengthFieldOffset 偏移量(单位:字节)
	 * @param lengthFieldLength 长度字节
	 * @param lengthAdjustment 修正字节
	 * @param initialBytesToStrip 设置返回字节从哪个位置开始
	 * @param failFast 为true:当frame长度超过maxFrameLength时立即报TooLongFrameException异常。为false:读取完整个帧再报异
	 */
	public LengthFieldBasedFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
		this(ByteOrder.BIG_ENDIAN, maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast);
	}

	/**
	 * @param byteOrder
	 * @param maxFrameLength      最大字节
	 * @param lengthFieldOffset   偏移量(单位:字节)
	 * @param lengthFieldLength   长度字节
	 * @param lengthAdjustment    修正字节
	 * @param initialBytesToStrip 设置返回字节从哪个位置开始
	 * @param failFast 为true:当frame长度超过maxFrameLength时立即报TooLongFrameException异常。为false:读取完整个帧再报异
	 */
	public LengthFieldBasedFrameDecoder(ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
		if (byteOrder == null) {
			throw new NullPointerException("byteOrder");
		} else {
			ObjectUtil.checkPositive(maxFrameLength, "maxFrameLength");
			ObjectUtil.checkPositiveOrZero(lengthFieldOffset, "lengthFieldOffset");
			ObjectUtil.checkPositiveOrZero(initialBytesToStrip, "initialBytesToStrip");
			if (lengthFieldOffset > maxFrameLength - lengthFieldLength) {
				throw new IllegalArgumentException("maxFrameLength (" + maxFrameLength + ") must be equal to or greater than lengthFieldOffset (" + lengthFieldOffset + ") + lengthFieldLength (" + lengthFieldLength + ").");
			} else {
				this.byteOrder = byteOrder;
				this.maxFrameLength = maxFrameLength;
				this.lengthFieldOffset = lengthFieldOffset;
				this.lengthFieldLength = lengthFieldLength;
				this.lengthAdjustment = lengthAdjustment;
				this.lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength;
				this.initialBytesToStrip = initialBytesToStrip;
				this.failFast = failFast;
			}
		}
	}

	/**
	 * 解码
	 *
	 * @param ctx 通道
	 * @param in  需要解析的字节
	 * @param out 输出信息
	 * @throws Exception
	 */
	protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
		//调用内部的解码方法,解码成功,将其加入到输出List<Object> out列表中
		Object decoded = this.decode(ctx, in);
		if (decoded != null) {
			out.add(decoded);
		}
	}

	/**
	 * 丢弃忽略的字节
	 *
	 * @param in
	 */
	private void discardingTooLongFrame(ByteBuf in) {
		//丢弃的长度
		long bytesToDiscard = this.bytesToDiscard;
		//由于丢弃的字节数不能大于当前缓存区可读的字节数,所以通过Math.min(x,y)来进行选择
		int localBytesToDiscard = (int) Math.min(bytesToDiscard, (long) in.readableBytes());
		//skipBytes方法跳过需要忽略的字节长度
		in.skipBytes(localBytesToDiscard);
		//减去已经忽略的字节长度
		bytesToDiscard -= (long) localBytesToDiscard;
		this.bytesToDiscard = bytesToDiscard;
		this.failIfNecessary(false);
	}

	private static void failOnNegativeLengthField(ByteBuf in, long frameLength, int lengthFieldEndOffset) {
		in.skipBytes(lengthFieldEndOffset);
		throw new CorruptedFrameException("negative pre-adjustment length field: " + frameLength);
	}

	private static void failOnFrameLengthLessThanLengthFieldEndOffset(ByteBuf in, long frameLength, int lengthFieldEndOffset) {
		in.skipBytes(lengthFieldEndOffset);
		throw new CorruptedFrameException("Adjusted frame length (" + frameLength + ") is less than lengthFieldEndOffset: " + lengthFieldEndOffset);
	}

	/**
	 * 丢弃策略
	 * @param in
	 * @param frameLength 数据的长度
	 */
	private void exceededFrameLength(ByteBuf in, long frameLength) {
		//丢弃的长度=计算出的长度-可读的长度
		long discard = frameLength - (long) in.readableBytes();
		//计算出来的长度
		this.tooLongFrameLength = frameLength;
		if (discard < 0L) {
			//丢弃的字节小于0
			//直接忽略整个 计算长读
			in.skipBytes((int) frameLength);
		} else {
			//标记为true,表示下次解码的时候需要继续丢弃
			this.discardingTooLongFrame = true;
			//忽略字节的长度
			this.bytesToDiscard = discard;
			//跳过该字节流的所有字节
			in.skipBytes(in.readableBytes());
		}
		//根据实际情况抛出异常
		this.failIfNecessary(true);
	}

	/**
	 * 忽略当前的数据报,并抛出CorruptedFrameException异常
	 * @param in
	 * @param frameLength
	 * @param initialBytesToStrip
	 */
	private static void failOnFrameLengthLessThanInitialBytesToStrip(ByteBuf in, long frameLength, int initialBytesToStrip) {
		in.skipBytes((int) frameLength);
		throw new CorruptedFrameException("Adjusted frame length (" + frameLength + ") is less than initialBytesToStrip: " + initialBytesToStrip);
	}

	protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
		//是否丢弃处理
		if (this.discardingTooLongFrame) {
			this.discardingTooLongFrame(in);
		}
		//对当前可读字节数和长度偏移量(偏移量字段+长度字节长度)进行对比,如果小于长度偏移量,说明当前缓冲区的数据不够,返回null
		//由I/O线程继续读取后续数据报
		if (in.readableBytes() < this.lengthFieldEndOffset) {
			return null;
		} else {
			//in.readerIndex():获取读索引
			//实际读取的索引位置=读索引+偏移量
			int actualLengthFieldOffset = in.readerIndex() + this.lengthFieldOffset;
			//通过索引值获取消息报文的长度字段
			long frameLength = this.getUnadjustedFrameLength(in, actualLengthFieldOffset, this.lengthFieldLength, this.byteOrder);
			if (frameLength < 0L) {
				//长度小于0,说明报文非法
				failOnNegativeLengthField(in, frameLength, this.lengthFieldEndOffset);
			}
			// 实际长度=调整长度+偏移量+长度
			frameLength += (long) (this.lengthAdjustment + this.lengthFieldEndOffset);
			if (frameLength < (long) this.lengthFieldEndOffset) {
				//修正后的长度小于长度偏移量,为非法报文
				failOnFrameLengthLessThanLengthFieldEndOffset(in, frameLength, this.lengthFieldEndOffset);
			}

			if (frameLength > (long) this.maxFrameLength) {
				//长度大于最大容量
				//消息长度大于系统允许的最大长度上限,需要设置discardingTooLongFrame.
				this.exceededFrameLength(in, frameLength);
				return null;
			} else {
				int frameLengthInt = (int) frameLength;
				if (in.readableBytes() < frameLengthInt) {
					//可读字段小于frameLength,说明是半包信息,需要返回空,由I/O线程继续读取后续的数据报,等到下次解码
					return null;
				} else {
					if (this.initialBytesToStrip > frameLengthInt) {
						//对需要忽略的消息头字段进行判断,如果大于消息长度frameLengthInt,说明码流非法
						failOnFrameLengthLessThanInitialBytesToStrip(in, frameLength, this.initialBytesToStrip);
					}
					//忽略设置的字节流
					in.skipBytes(this.initialBytesToStrip);
					//获取读取的索引
					int readerIndex = in.readerIndex();
					//实际读取字节的长度
					int actualFrameLength = frameLengthInt - this.initialBytesToStrip;
					//根据消息的实际长度分配一个新的ByteBuf对象
					ByteBuf frame = this.extractFrame(ctx, in, readerIndex, actualFrameLength);
					in.readerIndex(readerIndex + actualFrameLength);
					return frame;
				}
			}
		}
	}

	/**
	 * 根据长度字段,获取自身的字节长度
	 * @param buf    数据流
	 * @param offset 开始读索引的位置
	 * @param length 长度
	 * @param order
	 * @return
	 */
	protected long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) {
		//设置缓冲区字节序
		buf = buf.order(order);
		long frameLength;
		switch (length) {
			case 1:
				frameLength = (long) buf.getUnsignedByte(offset);
				break;
			case 2:
				frameLength = (long) buf.getUnsignedShort(offset);
				break;
			case 3:
				frameLength = (long) buf.getUnsignedMedium(offset);
				break;
			case 4:
				frameLength = buf.getUnsignedInt(offset);
				break;
			case 5:
			case 6:
			case 7:
			default:
				throw new DecoderException("unsupported lengthFieldLength: " + this.lengthFieldLength + " (expected: 1, 2, 3, 4, or 8)");
			case 8:
				frameLength = buf.getLong(offset);
		}

		return frameLength;
	}

	/**
	 * 判断是否已经达到需要忽略的字节数
	 *
	 * @param firstDetectionOfTooLongFrame
	 */
	private void failIfNecessary(boolean firstDetectionOfTooLongFrame) {
		if (this.bytesToDiscard == 0L) {
			long tooLongFrameLength = this.tooLongFrameLength;
			this.tooLongFrameLength = 0L;
			this.discardingTooLongFrame = false;
			if (!this.failFast || firstDetectionOfTooLongFrame) {
				this.fail(tooLongFrameLength);
			}
		} else if (this.failFast && firstDetectionOfTooLongFrame) {
			this.fail(this.tooLongFrameLength);
		}

	}

	/**
	 * 创建新的ByteBuf
	 * @param ctx
	 * @param buffer 原ByteBuf数据报
	 * @param index 起始位置
	 * @param length 长度
	 * @return
	 */
	protected ByteBuf extractFrame(ChannelHandlerContext ctx, ByteBuf buffer, int index, int length) {
		//返回当前ByteBuf的可读子缓存区,起始位置从index到index+length
		//返回后的ByteBuf与原ByteBuf共享。
		return buffer.retainedSlice(index, length);
	}

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

个人能力有限,注释不对的地方。欢迎评论区指正。

发布了3 篇原创文章 · 获赞 1 · 访问量 66

猜你喜欢

转载自blog.csdn.net/langzhouxing/article/details/103698508
今日推荐