【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无限制积压,引起系统内存溢出。
Ntty源码还在学习,这篇内容分析的不是很全面,后期还会对这篇文章进行补写。
工作原理
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源码还在学习,这篇内容分析的不是很全面,后期还会对这篇文章进行补写。
相关文章推荐
- 剑指offer之面试题19:二叉树的镜像
- Velocity #foreach指令
- Codevs 2370 小机房的树
- 使用windows套接字进行网络编程
- Mysql数据库在cmd操作(一)
- Windows 2008 下 P2V windows 2003系统
- SQL SERVER 2008如何建立自动备份的维护计划
- 去除list里面的重复数组的性能比较
- css3-loading效果
- 单调队列: Sliding Window
- 设计模式--策略模式
- LCD 常用的客观效果指标和测试方法
- 【训练题】二分图判定
- UE4中dynamic create component及ChildActorComponent未解析符号 问题
- typescript学习视频
- python 模拟ajax请求
- 杭电1018 BIG NUMBER
- 工具使用-Maven打包问题
- LCD 常用的客观效果指标和测试方法
- 牛人经验3(IC设计行业分类辨析)