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");
}
}
}
个人能力有限,注释不对的地方。欢迎评论区指正。