Netty-源码分析DelimiterBasedFrameDecoder
Posted 征服.刘华强
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Netty-源码分析DelimiterBasedFrameDecoder相关的知识,希望对你有一定的参考价值。
DelimiterBasedFrameDecoder自定义分隔符解码器
package io.netty.handler.codec;
import static io.netty.util.internal.ObjectUtil.checkPositive;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import java.util.List;
//自定义分隔符解码器
public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder
//自定义的分隔符,可以使用多个
private final ByteBuf[] delimiters;
//每个消息段落最大长度
private final int maxFrameLength;
//解码消息时,是否丢弃分隔符
private final boolean stripDelimiter;
//遇到错误时,是否抛出异常
private final boolean failFast;
//状态变量-是否正在丢弃一个段的消息
private boolean discardingTooLongFrame;
//丢弃总长度
private int tooLongFrameLength;
//\\r\\n的解码器
private final LineBasedFrameDecoder lineBasedDecoder;
public DelimiterBasedFrameDecoder(
int maxFrameLength, boolean stripDelimiter, boolean failFast, ByteBuf... delimiters)
validateMaxFrameLength(maxFrameLength);
if (delimiters == null)
throw new NullPointerException("delimiters");
if (delimiters.length == 0)
throw new IllegalArgumentException("empty delimiters");
//delimiters里的分隔符 是否是\\r\\n
if (isLineBased(delimiters) && !isSubclass())
lineBasedDecoder = new LineBasedFrameDecoder(maxFrameLength, stripDelimiter, failFast);
this.delimiters = null;
else
//创建数组
this.delimiters = new ByteBuf[delimiters.length];
for (int i = 0; i < delimiters.length; i ++)
ByteBuf d = delimiters[i];
validateDelimiter(d);
//创建d的分区放入数组
this.delimiters[i] = d.slice(d.readerIndex(), d.readableBytes());
lineBasedDecoder = null;
this.maxFrameLength = maxFrameLength;
this.stripDelimiter = stripDelimiter;
this.failFast = failFast;
//判断是否是Delimiters.lineDelimiter()
/** Returns true if the delimiters are "\\n" and "\\r\\n". */
private static boolean isLineBased(final ByteBuf[] delimiters)
if (delimiters.length != 2)
return false;
ByteBuf a = delimiters[0];
ByteBuf b = delimiters[1];
if (a.capacity() < b.capacity())
a = delimiters[1];
b = delimiters[0];
return a.capacity() == 2 && b.capacity() == 1
&& a.getByte(0) == '\\r' && a.getByte(1) == '\\n'
&& b.getByte(0) == '\\n';
//判断是否是子类
private boolean isSubclass()
return getClass() != DelimiterBasedFrameDecoder.class;
@Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception
Object decoded = decode(ctx, in);
if (decoded != null)
out.add(decoded);
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception
//如果分隔符是\\r\\n则用lineBasedDecoder解码器解析
//此类就相当于lineBasedDecoder
if (lineBasedDecoder != null)
return lineBasedDecoder.decode(ctx, buffer);
int minFrameLength = Integer.MAX_VALUE;
ByteBuf minDelim = null;
//循环所有分隔符,挨个去匹配
for (ByteBuf delim: delimiters)
//匹配分隔符的起始位置
int frameLength = indexOf(buffer, delim);
//大于0,并且小于int最大值 说明匹配成功
if (frameLength >= 0 && frameLength < minFrameLength)
minFrameLength = frameLength;
minDelim = delim;
//说明匹配成功
if (minDelim != null)
//分隔符的capacity就代表了分隔符的长度
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;
//跳过minFrameLength+分隔符的长度,表示丢弃了前一个完整的消息
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
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
//之前discardingTooLongFrame已经设置为true
// Still discarding the buffer since a delimiter is not found.
//增加总丢弃数量
tooLongFrameLength += buffer.readableBytes();
//继续丢弃字节
buffer.skipBytes(buffer.readableBytes());
return null;
private void fail(long frameLength)
if (frameLength > 0)
throw new TooLongFrameException(
"frame length exceeds " + maxFrameLength +
": " + frameLength + " - discarded");
else
throw new TooLongFrameException(
"frame length exceeds " + maxFrameLength +
" - discarding");
private static int indexOf(ByteBuf haystack, ByteBuf needle)
//循环输入的字节流缓冲区,假设 a b c d e
for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i ++)
//从[a] 0位置开始找
int haystackIndex = i;
int needleIndex;
//循环分隔符
for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex ++)
//如果分隔符与haystack.getByte(haystackIndex)不同,则结束当前循环
//haystack.getByte(haystackIndex) 从b开始继续查询
if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex))
break;
else
haystackIndex ++;
//依次拿出bcde进行匹配,如果输入缓冲区到达末尾,并且分隔符缓冲区还没有到达末尾,说明匹配失败
if (haystackIndex == haystack.writerIndex() &&
needleIndex != needle.capacity() - 1)
return -1;
//如果分隔符缓冲区达到末尾,还没发生上面的情况,说明匹配到了
if (needleIndex == needle.capacity())
// Found the needle from the haystack!
//i减去haystack.readerIndex()的位置就是分隔符的位置
return i - haystack.readerIndex();
return -1;
以上是关于Netty-源码分析DelimiterBasedFrameDecoder的主要内容,如果未能解决你的问题,请参考以下文章