netty系列之:内置的Frame detection
简介
上篇文章我们讲到了netty中怎么自定义编码和解码器,但是自定义实现起来还是挺复杂的,一般没有特殊必要的情况下,大家都希望越简单越好,其难点就是找到ByteBuf中的分割点,将ByteBuf分割成为一个个的可以处理的单元。今天本文讲讲netty中自带的分割处理机制。
Frame detection
在上一章,我们提到了需要有一种手段来区分ByteBuf中不同的数据,也就是说找到ByteBuf中不同数据的分割点。如果首先将ByteBuf分割成一个个的独立的ByteBuf,再对独立的ByteBuf进行处理就会简单很多。
netty中提供了4个分割点的编码器,我们可以称之为Frame detection,他们分别是DelimiterBasedFrameDecoder, FixedLengthFrameDecoder, LengthFieldBasedFrameDecoder, 和 LineBasedFrameDecoder。
这几个类都是ByteToMessageDecoder的子类,接下来我们一一进行介绍。
DelimiterBasedFrameDecoder
首先是DelimiterBasedFrameDecoder,看名字就知道这个是根据delimiter对bytebuf进行分割的解码器。什么是delimiter呢?
netty中有一个Delimiters类,专门定义分割的字符,主要有两个delimiter,分别是nulDelimiter和lineDelimiter:
public static ByteBuf[] nulDelimiter() {
return new ByteBuf[] {
Unpooled.wrappedBuffer(new byte[] { 0 }) };
}
public static ByteBuf[] lineDelimiter() {
return new ByteBuf[] {
Unpooled.wrappedBuffer(new byte[] { '\r', '\n' }),
Unpooled.wrappedBuffer(new byte[] { '\n' }),
};
}
nullDelimiter用来处理0x00,主要用来处理Flash XML socket或者其他的类似的协议。
lineDelimiter用来处理回车和换行符,主要用来文本文件的处理中。
对于DelimiterBasedFrameDecoder来说,如果有多个delimiter的话,会选择将ByteBuf分割最短的那个,举个例子,如果我们使用DelimiterBasedFrameDecoder(Delimiters.lineDelimiter()) ,因为lineDelimiter中实际上有两个分割方式,回车+换行或者换行,如果遇到下面的情况:
+--------------+
| ABC\nDEF\r\n |
+--------------+
DelimiterBasedFrameDecoder会选择最短的分割结果,也就说将上面的内容分割成为:
+-----+-----+
| ABC | DEF |
+-----+-----+
而不是
+----------+
| ABC\nDEF |
+----------+
FixedLengthFrameDecoder
这个类会将ByteBuf分成固定的长度,比如收到了下面的4块byte信息:
+---+----+------+----+
| A | BC | DEFG | HI |
+---+----+------+----+
如果使用一个FixedLengthFrameDecoder(3) ,则会将上面的ByteBuf分成下面的几个部分:
+-----+-----+-----+
| ABC | DEF | GHI |
+-----+-----+-----+
LengthFieldBasedFrameDecoder
这个类就更加灵活一点,可以根据数据中的length字段取出后续的byte数组。LengthFieldBasedFrameDecoder非常灵活,它有4个属性来控制他们分别是lengthFieldOffset、lengthFieldLength、lengthAdjustment和initialBytesToStrip。
lengthFieldOffset是长度字段的起始位置,lengthFieldLength是长度字段本身的长度,lengthAdjustment是对目标数据长度进行调整,initialBytesToStrip是解密过程中需要删除的byte数目。理解不了?没关系,我们来举几个例子。
首先看一个最简单的:
lengthFieldOffset = 0
lengthFieldLength = 2
lengthAdjustment = 0
initialBytesToStrip = 0
BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)
+--------+----------------+ +--------+----------------+
| Length | Actual Content |----->| Length | Actual Content |
| 0x000C | "HELLO, WORLD" | | 0x000C | "HELLO, WORLD" |
+--------+----------------+ +--------+----------------+
上面的设置表示,length是从第0位开始的,长度是2个字节。其中Ox00C=12, 这也是“HELLO, WORLD” 的长度。
如果不想要Length字段,可以通过设置initialBytesToStrip把length删除:
lengthFieldOffset = 0
lengthFieldLength = 2
lengthAdjustment = 0
initialBytesToStrip = 2 (= length 字段的长度)
BEFORE DECODE (14 bytes) AFTER DECODE (12 bytes)
+--------+----------------+ +----------------+
| Length | Actual Content |----->| Actual Content |
| 0x000C | "HELLO, WORLD" | | "HELLO, WORLD" |
+--------+----------------+ +----------------+
lengthAdjustment是对Length字段的值进行调整,因为在有些情况下Length字段可能包含了整条数据的长度,也就是Length+内容,所以需要在解析的时候进行调整,比如下面的例子,真实长度其实是0x0C,但是传入的却是0x0E,所以需要减去Length字段的长度2,也就是将lengthAdjustment设置为-2。
lengthFieldOffset = 0
lengthFieldLength = 2
lengthAdjustment = -2 (= Length字段的长度)
initialBytesToStrip = 0
BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)
+--------+----------------+ +--------+----------------+
| Length | Actual Content |----->| Length | Actual Content |
| 0x000E | "HELLO, WORLD" | | 0x000E | "HELLO, WORLD" |
+--------+----------------+ +--------+----------------+
LineBasedFrameDecoder
LineBasedFrameDecoder专门处理文本文件中的一行结束。也就是 "\n" 和 "\r\n",他和DelimiterBasedFrameDecoder很类似,但是DelimiterBasedFrameDecoder更加通用。
总结
有了上面4个Frame detection装置之后,就可以在pipline中首先添加这些Frame detection,然后再添加自定义的handler,这样在自定义的handler中就不用考虑读取ByteBuf的长度问题了。
比如在StringDecoder中,如果已经使用了 LineBasedFrameDecoder , 那么在decode方法中可以假设传入的ByteBuf就是一行字符串,那么可以直接这样使用:
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
out.add(msg.toString(charset));
}
是不是很简单?
本文已收录于 http://www.flydean.com/15-netty-buildin-frame-detection/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
netty系列之:内置的Frame detection的更多相关文章
- 面向对象 反射 和item系列和内置函数和__getattr__和__setattr__
反射 反射主要用在网络编程中, python面向对象的反射:通过字符串的形式操作对象相关的属性.python的一切事物都是对象. 反射就是通过字符串的形式,导入模块:通过字符串的形式,去模块寻找指定函 ...
- Python系列-python内置函数
abs(x) 返回数字的绝对值,参数可以是整数.也可以是浮点数.如果是复数,则返回它的大小 all(iterable) 对参数中的所有元素进行迭代,如果所有的元素都是True,则返回True,函数等价 ...
- 小飞侠带你精通Python网络编程系列04-Python内置的数据类型
在Python中有以下几种标准的内置数据类型: 1.NoneType: The Null object--空对象2.Numerics(数值): int-整数, long-长整数, float-浮点数, ...
- 【LESS系列】内置函数说明
本文转自 http://www.cnblogs.com/zfc2201/p/3493335.html escape(@string); // 通过 URL-encoding 编码字符串 e(@stri ...
- Python3入门系列之-----内置的文件操作模块OS
前言 在自动化测试中,经常需要查找操作文件,比如说查找配置文件(从而读取配置文件的信息),查找测试报告(从而发送测试报告邮件),经常要对大量文件和大量路径进行操作,这个时候就需要用到os模块. 使用前 ...
- SQL基础系列(2)-内置函数--转载w3school
1. 日期函数 Mssql: SELECT GETDATE() 返回当前日期和时间 SELECT DATEPART(yyyy,OrderDate) AS OrderYear, DATEPART( ...
- netty系列之:netty中的懒人编码解码器
目录 简介 netty中的内置编码器 使用codec要注意的问题 netty内置的基本codec base64 bytes compression json marshalling protobuf ...
- netty系列之:netty架构概述
目录 简介 netty架构图 丰富的Buffer数据机构 零拷贝 统一的API 事件驱动 其他优秀的特性 总结 简介 Netty为什么这么优秀,它在JDK本身的NIO基础上又做了什么改进呢?它的架构和 ...
- day006 数字类型和字符串类型的内置方法
首先,为什么要有数据类型? 对于不同类型的变量,需要用不同的数据类型去描述. 数字类型的内置方法 数据类型又分为整形和浮点型.以下所述的内置方法均适用于这两个类型. 必须掌握的方法*** 数据类型有基 ...
随机推荐
- 第二届 BJD wp(reverse和crypto)
re 1.第一题拖入ida,flag就是直接明文摆着 2.第二题是8086的程序,拖入ida,发现有个jmp无限跳转,可能是段寄存器被修改了,ida无法将后面的汇编识别出来,所以后面才有很多无效数据, ...
- 刷算法,这些api不可不知!
大家好,我是老三,最近在刷算法,发现有些api记得不熟,所以整理了一波,如果你也在刷题,赶紧收藏吧! 集合 在刷题中,各种数据结构是我们常常用到的,例如栈实现迭代.哈希存储键值对等等,我们来看看常用集 ...
- 建立第一个SCRAPY的具体过程
1.安装SCRAPY2.进入CMD:执行:SCRAPY显示: Scrapy 1.8.0 - no active project Usage: scrapy <command> [optio ...
- asp.net c# 保存图片到sql2008
//图像数据表:tx//字段id (nvarchar(50) ,image(image)//tgav为图片ID,实质为上传前的主名 (省略了.jpg)private void kkkkk(byte[] ...
- excel vslookup应用举例
excel vslookup应用举例 =vslookup("第一个需要查找的对象","查找的区域范围","查找的最终目标在区域的第几列",& ...
- Java程序设计当堂测试感受
开学第一周的周四,按照王主任的安排,进行了Java当堂测试,来检测暑假八周的学习成果.这一堂课真是让我哭笑不得,这一节课三个小时都在写代码,感觉暑假学的一点点代码什么都不是,写一个系统都完不成,感觉自 ...
- Java基础00-常用API24
1. Math Math 1.1 Math类概述 1.2 Math类的常用方法 返回绝对值:是正数是时候直接返回参数本身,是负值的时候返回的是参数的相反数.参数是10时返回的是10,参数是-10的时候 ...
- 如何进行TIDB优化之Grafana(TiDB 3.0)关注监控指标
前言 在对数据库进行优化前,我们先要思考一下数据库系统可能存在的瓶颈所在之外.数据库服务是运行在不同的硬件设备上的,优化即通过参数配置(不考虑应用客户端程序的情况下),而实现硬件资源的最大利用化.那么 ...
- Web的工作原理(二)
1.工作过程:如下图所示描述了Web的工作原理. (1) 用户打开计算机(客户机),启动浏览器程序,并在浏览器中指定一个URL(Uniform Resource Locator,统一资源定位器),浏览 ...
- 第九篇 -- 对数据库mysql进行连接并压测(二)
上一节介绍了对mysql查询语句的压测,这一节来进一步的了解. 还是先把数据库的图放上来. 接下来打开Jmeter. 1. 回顾一下上一节学的查询语句 JDBC Request配置 结果 2. 条件查 ...