Netty LengthFieldBasedFrameDecoder
先看看LengthFieldBasedFrameDecoder的官方API
http://docs.jboss.org/netty/3.1/api/org/jboss/netty/handler/codec/frame/LengthFieldBasedFrameDecoder.html
API举例说明了LengthFieldBasedFrameDecoder的解析机制,如下:
实际消息内容是“HELLO, WORLD”,长度是12 bytes(注意逗号后面有一个空格)
实例1
lengthFieldLength = 2表示“Length”的长度,而“Length”的值
就是“Actual Content”的长度(0x000C, 也就是12):
Java代码 ![](http://bylijinnan.iteye.com/images/icon_star.png)
- lengthFieldOffset = 0
- lengthFieldLength = 2
- lengthAdjustment = 0
- initialBytesToStrip = 0 (= do not strip header)
- BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)
- +--------+----------------+ +--------+----------------+
- | Length | Actual Content |----->| Length | Actual Content |
- | 0x000C | "HELLO, WORLD" | | 0x000C | "HELLO, WORLD" |
- +--------+----------------+ +--------+----------------+
实例2
initialBytesToStrip = 2 表示在decode时,要去掉多少个字节
在这个例子,表示要去掉“Length”(2个字节)
可以看到,AFTER DECODE后,“Length”没有了,只剩下“Actual Content”:
![](http://bylijinnan.iteye.com/images/icon_star.png)
- lengthFieldOffset = 0
- lengthFieldLength = 2
- lengthAdjustment = 0
- initialBytesToStrip = 2 (= the length of the Length field)
- BEFORE DECODE (14 bytes) AFTER DECODE (12 bytes)
- +--------+----------------+ +----------------+
- | Length | Actual Content |----->| Actual Content |
- | 0x000C | "HELLO, WORLD" | | "HELLO, WORLD" |
- +--------+----------------+ +----------------+
实例3
与实例1不同,这里“Length”的值不是“Actual Content”的长度,而是
整个消息的长度(0x000E,14 = 2 + 12)。用lengthAdjustment=-2来表示
“Actual Content”的长度要减2:
wholeLength = valueOf(Length) = 14
actualContentLength = wholeLength + lengthAdjustment = 14 + (-2)=12
![](http://bylijinnan.iteye.com/images/icon_star.png)
- lengthFieldOffset = 0
- lengthFieldLength = 2
- lengthAdjustment = -2 (= the length of the Length field)
- initialBytesToStrip = 0
- BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)
- +--------+----------------+ +--------+----------------+
- | Length | Actual Content |----->| Length | Actual Content |
- | 0x000E | "HELLO, WORLD" | | 0x000E | "HELLO, WORLD" |
- +--------+----------------+ +--------+----------------+
实例4
这个例子多了一个“Header 1”(oxCAFE,长度为2 )
用 lengthFieldOffset = 2表示“Length”从第3个字节开始
“Length”的值仍然是“Actual Content ”的长度,不过“Length”自身的
长度是3 (值是0x00000C,而不是上面的0x000C)
![](http://bylijinnan.iteye.com/images/icon_star.png)
- lengthFieldOffset = 2 (= the length of Header 1)
- lengthFieldLength = 3
- lengthAdjustment = 0
- initialBytesToStrip = 0
- BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes)
- +----------+----------+----------------+ +----------+----------+----------------+
- | Header 1 | Length | Actual Content |----->| Header 1 | Length | Actual Content |
- | 0xCAFE | 0x00000C | "HELLO, WORLD" | | 0xCAFE | 0x00000C | "HELLO, WORLD" |
- +----------+----------+----------------+ +----------+----------+----------------+
实例5
与实例4不同的地方是,“Length”和“Header 1”的位置调换了
wholeLength = valueOf(Length) = 14
actualContentLength = wholeLength + lengthAdjustment = 14 + 2=16
因此在decode时,会认为“Header 1”也是“Actual Content”的一部分
![](http://bylijinnan.iteye.com/images/icon_star.png)
- lengthFieldOffset = 0
- lengthFieldLength = 3
- lengthAdjustment = 2 (= the length of Header 1)
- initialBytesToStrip = 0
- BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes)
- +----------+----------+----------------+ +----------+----------+----------------+
- | Length | Header 1 | Actual Content |----->| Length | Header 1 | Actual Content |
- | 0x00000C | 0xCAFE | "HELLO, WORLD" | | 0x00000C | 0xCAFE | "HELLO, WORLD" |
- +----------+----------+----------------+ +----------+----------+----------------+
实例6
看起来要比之前的例子复杂一些,但其实是上面例子的组合
lengthFieldOffset = 1表示“Length”从第2个字节开始
lengthFieldLength = 2表示“Length”的长度是2
lengthAdjustment = 1表示“HDR2”的长度是1:
wholeLength = valueOf(Length) = 0x000C = 12
actualContentLength = wholeLength + lengthAdjustment = 12 + 1=13
decode时,会认为“Length”后面的13个字节都是“Actual Content”,
因此会认为“HDR2”也是“Actual Content”的一部分
initialBytesToStrip = 3 表示decode时,去掉3个字节
![](http://bylijinnan.iteye.com/images/icon_star.png)
- lengthFieldOffset = 1 (= the length of HDR1)
- lengthFieldLength = 2
- lengthAdjustment = 1 (= the length of HDR2)
- initialBytesToStrip = 3 (= the length of HDR1 + LEN)
- BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes)
- +------+--------+------+----------------+ +------+----------------+
- | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
- | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" |
- +------+--------+------+----------------+ +------+----------------+
实例7
与实例6不同的是,lengthAdjustment = -3,是负数
因此,
wholeLength = valueOf(Length) = 0x0010 = 16
actualContentLength = wholeLength + lengthAdjustment = 16 + (-3)=13
decode时,会认为“Length”后面的13个字节都是“Actual Content”,
最终效果与实例6一样
![](http://bylijinnan.iteye.com/images/icon_star.png)
- lengthFieldOffset = 1
- lengthFieldLength = 2
- lengthAdjustment = -3 (= the length of HDR1 + LEN, negative)
- initialBytesToStrip = 3
- BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes)
- +------+--------+------+----------------+ +------+----------------+
- | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
- | 0xCA | 0x0010 | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" |
- +------+--------+------+----------------+ +------+----------------+
API看完,我们来看看源码(只保留关键代码):
![](http://bylijinnan.iteye.com/images/icon_star.png)
- public class LengthFieldBasedFrameDecoder extends FrameDecoder {
- private final int maxFrameLength; //超出此长度的Frame将被丢弃
- private final int lengthFieldOffset;
- private final int lengthFieldLength;
- private final int lengthFieldEndOffset; //这个值等于lengthFieldOffset + lengthFieldLength
- private final int lengthAdjustment;
- private final int initialBytesToStrip;
- protected Object decode(
- ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
- //数据未完整,先不处理
- if (buffer.readableBytes() < lengthFieldEndOffset) {
- return null;
- }
- /*
- 先读取“Length”的值
- 在LengthFieldBasedFrameDecoder的构造函数中,限定了“Length”的长度:
- “lengthFieldLength must be either 1, 2, 3, 4, or 8”
- 单位是bytes。这个限定不知从何而来,先不管
- 由于接收到的数据的类型是ChannelBuffer,也就是byte[],那么在读取时,
- 就应该根据长度来分割数据
- 例如,lengthFieldLength=3,说明读取前3个字节就得到“Length”的值
- 读取时,用到了位操作,ByteOrder是BIG_ENDIAN,因此高位在前,要左移位:
- public int getUnsignedMedium(int index) {
- return (array[index] & 0xff) << 16 |
- (array[index + 1] & 0xff) << 8 |
- (array[index + 2] & 0xff) << 0;
- }
- 注意到,这个方法不会改变readerIndex
- 下面代码的frameLength,其实就是上面API分析时提到的valueOf(Length)
- */
- int actualLengthFieldOffset = buffer.readerIndex() + lengthFieldOffset;
- long frameLength;
- switch (lengthFieldLength) {
- case 1:
- frameLength = buffer.getUnsignedByte(actualLengthFieldOffset);
- break;
- case 2:
- frameLength = buffer.getUnsignedShort(actualLengthFieldOffset);
- break;
- case 3:
- frameLength = buffer.getUnsignedMedium(actualLengthFieldOffset);
- break;
- case 4:
- frameLength = buffer.getUnsignedInt(actualLengthFieldOffset);
- break;
- case 8:
- frameLength = buffer.getLong(actualLengthFieldOffset);
- break;
- default:
- throw new Error("should not reach here");
- }
- //如分析API时所说,要加上lengthAdjustment
- //那为什么 还要加上lengthFieldEndOffset?
- //加上之后,frameLength就代表整个frame的长度了,包括前缀和“Actual Content”
- frameLength += lengthAdjustment + lengthFieldEndOffset;
- int frameLengthInt = (int) frameLength;
- //数据未完整,先不处理
- if (buffer.readableBytes() < frameLengthInt) {
- return null;
- }
- //readerIndex往后移,跳过指定的字节,不读取
- buffer.skipBytes(initialBytesToStrip);
- // extract frame ,读取消息的内容
- int readerIndex = buffer.readerIndex();
- int actualFrameLength = frameLengthInt - initialBytesToStrip;
- ChannelBuffer frame = extractFrame(buffer, readerIndex, actualFrameLength);
- //extractFrame方法不改变buffer的readerIndex,因此要手动设置
- buffer.readerIndex(readerIndex + actualFrameLength);
- return frame;
- }
- //这个方法创建了新的ChannelBuffer,不影响原buffer
- protected ChannelBuffer extractFrame(ChannelBuffer buffer, int index, int length) {
- ChannelBuffer frame = buffer.factory().getBuffer(length);
- frame.writeBytes(buffer, index, length);
- return frame;
- }
- }
Netty LengthFieldBasedFrameDecoder相关推荐
- Netty——LengthFieldBasedFrameDecoder
先看看LengthFieldBasedFrameDecoder的官方API http://docs.jboss.org/netty/3.1/api/org/jboss/netty/handler/c ...
- Netty源码学习-LengthFieldBasedFrameDecoder
先看看LengthFieldBasedFrameDecoder的官方API [url]http://docs.jboss.org/netty/3.1/api/org/jboss/netty/handl ...
- Netty源码(十一)之LengthFieldBasedFrameDecoder/LengthFieldPrepender
1.前文 前两篇博客我介绍了三种解码器,分别是基于固定长度的解码器(FixedLengthFrameDecoder),基于行的解码器(LineBasedFrameDecoder),基于分割符解码器(D ...
- netty粘包拆包之LengthFieldBasedFrameDecoder解码器
目录 一. 背景简介 二. 应用 三.源码 一.背景简介 LengthFieldBasedFrameDecoder 基于长度字段解码器,是 ...
- Netty源码分析系列之常用解码器(下)——LengthFieldBasedFrameDecoder
扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,Spring源码分析和Java并发编程文章. 前言 在上一篇文章中分析了三个比较简单的解码器,今天接着分析最后一个常用的解码器:Leng ...
- netty集成ssl完整参考指南(含完整源码)
虽然我们在内部rpc通信中使用的是基于认证和报文头加密的方式实现安全性,但是有些时候仍然需要使用SSL加密,可能是因为对接的三方系统需要,也可能是由于open的考虑.中午特地测了下netty下集成ss ...
- Netty 粘包 拆包 编码 解码 序列化 介绍
目录: 粘包 & 拆包及解决方案 ByteToMessageDecoder 基于长度编解码器 基于分割符的编解码器 google 的 Protobuf 序列化介绍 其他的 前言 Netty 作 ...
- 附录G Netty与NettyUtils
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/beliefer/article/details/77450134 注:本文是为了配合<Spar ...
- 面试官问:服务的心跳机制与断线重连,Netty底层是怎么实现的?懵了
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 心跳机制 何为心跳 所谓心跳, 即在 TCP 长连接中, ...
最新文章
- 国内ntp时间服务器ip地址
- 高度平衡二叉树的构建_平衡二叉树(AVL)树
- Restful API的设计思路
- Oracle动态采样学习
- MyBatis 源码分析系列文章合集
- Java判断工作日计算,计算随意2个日期内的工作日
- B-树、B+树、B*树详解
- python课程水平测试成绩查询_学业水平考试成绩查询系统入口
- 界址点圆圈怎么生成_技巧|CASS10.1的界址点圆圈如何变细?
- 【渝粤题库】陕西师范大学164109人力资源管理 作业(高起专)
- 单片机课程设计八音盒
- Cluster sampling整群抽样例子
- php faker,laravel使用Faker数据填充的实现方法
- vb整合多个excel表格到一张_如何使用VB实现多个excel表格合并在一个EXCEL表格里面...
- 如何快速提高自己的领导力?
- 电脑插入耳机检测不到没反应怎么办?
- 前端css之 浮动 自学日记
- 高性能Nginx介绍(二)
- Linux下开MC服务器
- Xenu-web开发死链接检測工具应用
热门文章
- python基础实例教程 微课版-从零开始学Python(微课视频版)
- java 数字 字母 递增_JAVA流水号生成规则(按默认规则递增,数字不够添加字母递增,位数不够自动加1)...
- sunday算法特征码_sunday 算法
- 三维重建之条纹投影结构光(一)
- 【DSP实验】实验6音频信号处理实验-实现参量均衡器+滤波器+反相器的总和DSP处理交互系统
- 4、UML类图及类图之间的关系
- smarty php5.5,thinkphp5.1使用Smarty模板引擎
- popcap资源管理
- 局域网共享计算机指定,怎么把文件共享给工作局域网的特定人
- 医疗机构工作汇报PPT模板