LineBasedFrameDecoder源码分析
package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ByteProcessor;
import java.util.List;
//\r\n分割器,编码采用ASCII或者UTF-8,因为\r\n的ASCII,或UTF-8编码都是一致的。
//都是0D,0A,再0x7F[0111 1111]范围内,超过这个范围的码点采用DelimiterBasedFrameDecoder解码
public class LineBasedFrameDecoder extends ByteToMessageDecoder {
//每段消息的最大长度
private final int maxLength;
//超过最大长度是否抛出异常
/** Whether or not to throw an exception as soon as we exceed maxLength. */
private final boolean failFast = false;
//是否跳过分隔符
private final boolean stripDelimiter = true;
//true的话需要丢弃一部分字节,因为超过了每段消息的最大长度
/** True if we're discarding input because we're already over maxLength. */
private boolean discarding;
//丢弃字节的长度
private int discardedBytes;
//偏移量
/** Last scan position. */
private int offset;
@Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
//如果解析出decoded就放入out集合,父类会fire给下一个handler
Object decoded = decode(ctx, in);
if (decoded != null) {
out.add(decoded);
}
}
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
//查询\r\n的位置 假设消息为 "abcedf\r\n" 整体length=8 那么eol=6
final int eol = findEndOfLine(buffer);
//discarding=false 说明正常情况
if (!discarding) {
//查询到\r\n的位置
if (eol >= 0) {
final ByteBuf frame;
//6-0 = 6 是消息的长度
final int length = eol - buffer.readerIndex();
//eol的位置 如果是\r则分隔符2个字节, 否则一个字节。
final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
//如果消息长度 大于 每段消息的最大长度限制
if (length > maxLength) {
//把缓冲区readerIndex设置为0,相当于丢弃了前面的字节数据。
buffer.readerIndex(eol + delimLength);
//fire异常其它handler
fail(ctx, length);
return null;
}
//正常情况
//去掉分隔符
if (stripDelimiter) {
//返回子缓冲区,原始缓冲区的readerIndex会往后递增length个位置
//frame.refCnt=1 原始缓冲区的refCnt=2
//frame=[abcdef]
frame = buffer.readRetainedSlice(length);
//原始缓冲区丢弃delimLength长度的字节(丢弃分隔符)
buffer.skipBytes(delimLength);
} else {
//不丢弃分隔符,那么length需要在加上分隔符的长度 6+2=8
frame = buffer.readRetainedSlice(length + delimLength);
}
//返回子缓冲区
return frame;
} else {
//没找到分隔符位置
//可读字节长度
final int length = buffer.readableBytes();
//大于每段信息最大长度范围
if (length > maxLength) {
//记录需要丢弃的字节数
discardedBytes = length;
//跳过length个字节
buffer.readerIndex(buffer.writerIndex());
//设置标记
discarding = true;
offset = 0;
//抛异常
if (failFast) {
fail(ctx, "over " + discardedBytes);
}
}
return null;
}
} else { //进到这里,说明之前发生过特殊情况,需要丢弃一个消息
//找到了分隔符
if (eol >= 0) {
//discardedBytes是之前记录需要丢弃的字节数 [eol - buffer.readerIndex()]是分隔符前面的字节数
final int length = discardedBytes + eol - buffer.readerIndex();
//分隔符长度
final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
//丢弃分隔符之前的字节(包括分隔符)
buffer.readerIndex(eol + delimLength);
//重置标记变量
discardedBytes = 0;
discarding = false;
//抛异常
if (!failFast) {
fail(ctx, length);
}
} else {
//没找到分隔符
//增加discardedBytes的值 然后继续丢弃字节
discardedBytes += buffer.readableBytes();
buffer.readerIndex(buffer.writerIndex());
// We skip everything in the buffer, we need to set the offset to 0 again.
offset = 0;
}
return null;
}
}
//fire异常信息
private void fail(final ChannelHandlerContext ctx, int length) {
fail(ctx, String.valueOf(length));
}
private void fail(final ChannelHandlerContext ctx, String length) {
ctx.fireExceptionCaught(
new TooLongFrameException(
"frame length (" + length + ") exceeds the allowed maximum (" + maxLength + ')'));
}
private int findEndOfLine(final ByteBuf buffer) {
//buffer缓冲区中可读字节数
int totalLength = buffer.readableBytes();
//从readerIndex+offset开始,到totalLength - offset截止,默认offset=0,查找\n的位置
int i = buffer.forEachByte(buffer.readerIndex() + offset, totalLength - offset, ByteProcessor.FIND_LF);
//找到
if (i >= 0) {
offset = 0;
//看前一个字节是否是\r
if (i > 0 && buffer.getByte(i - 1) == '\r') {
//位置往前挪一位
i--;
}
} else {
//没找到- offset等于当前可读字节数
offset = totalLength;
}
return i;
}
}