您的位置:首页 > 其它

【Netty4.X】源码分析(三)之LineBasedFrameDecoder

2016-07-09 15:13 465 查看
在上一篇:【Netty4.X】TCP粘包/拆包问题的解决办法(二)文章中,我们在给ServerHandler之前添加了2个解码器LineBasedFrameDecoder和StringDecoder解决了服务器端粘包问题。今天我们就从源码上来分析LineBasedFrameDecoder。


工作原理

LineBasedFrameDecoder是回车换行解码器,如果用户发送的消息以回车换行符作为消息结束的标识,则可以直接使用Netty的LineBasedFrameDecoder对消息进行解码。它会依次遍历ByteBuf中的可读字节,判断看是否有“\n”或者“\r\n”,如果有,就以此位置为结束位置,从可读索引到结束位置区间的字节就组成了一行。它是以换行符为结束标志的解码器,支持携带结束符或者不携带结束符两种解码方式,同时支持配置单行的最大长度。如果连续读取到最大长度后仍然没有发现换行符,就会抛出异常,同时忽略掉之前读到的异常码流。防止由于数据报没有携带换行符导致接收到ByteBuf无限制积压,引起系统内存溢出。


变量解析

/** Maximum length of a frame we're willing to decode.  */
private final int maxLength;
/** Whether or not to throw an exception as soon as we exceed maxLength. */
private final boolean failFast;
private final boolean stripDelimiter;
/** True if we're discarding input because we're already over maxLength.  */
private boolean discarding;
private int discardedBytes;


变量名称说明
maxLength读取的最大长度,如果连续读取到最大长度后仍然没有发现换行符,就会抛出异常,同时忽略掉之前读到的异常码流
failFast如果设置成true,当发现解析的数据超过maxLenght就立马报错,否则当整个帧的数据解析完后才报错
stripDelimiter解码时是否去掉分隔符
discarding如果没有找到分隔符且读取的数据超过最大长度,我们将将其设置为true
discardedBytes从源码上分析它,见下

核心代码

protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
//先找到结束符索引
final int eol = findEndOfLine(buffer);
if (!discarding) {
//discarding默认为false,第一次必走这
if (eol >= 0) {
final ByteBuf frame;
final int length = eol - buffer.readerIndex();
final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
//
if (length > maxLength) {
buffer.readerIndex(eol + delimLength);
fail(ctx, length);
return null;
}

if (stripDelimiter) {
frame = buffer.readRetainedSlice(length);
buffer.skipBytes(delimLength);
} else {
frame = buffer.readRetainedSlice(length + delimLength);
}

return frame;
} else {
//没有找到结束符索引,通过ByteBuf.readableBytes()方法获取当前消息的长度
final int length = buffer.readableBytes();
//如果长度超过最大长度
if (length > maxLength) {
//使用discardedBytes临时存储消息的长度,并将discarding设置为true
discardedBytes = length;
buffer.readerIndex(buffer.writerIndex());
discarding = true;
if (failFast) {
fail(ctx, "over " + discardedBytes);
}
}
return null;
}
} else {
if (eol >= 0) {
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 += buffer.readableBytes();
buffer.readerIndex(buffer.writerIndex());
}
return null;
}
}


使用效果

解码前:
+------------------------------------------------------------------+
接收到的数据报
“ Hello Netty.\r\n Are you ok?”
+------------------------------------------------------------------+
解码后:
+------------------------------------------------------------------+
解码之后的文本消息
“Hello Netty.”
+------------------------------------------------------------------+


Ntty源码还在学习,这篇内容分析的不是很全面,后期还会对这篇文章进行补写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: