Netty 源码 ChannelHandler(四)编解码技术
Netty 源码 ChannelHandler(四)编解码技术
Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html)
一、拆包与粘包问题
由于 TCP 是面向字节流的,什么意思呢:虽然应用程序和 TCP 的交互是一次一个数据块(大小不等),但 TCP 把应用程序交下来的数据仅仅看成式一连串的无结构的字节流。TCP 并不知道所传送的字节流的含义。
因此 TCP 不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系(例如,发送方应用程序交给发送方的 TCP 共 10 个数据块,但接收方的 TCP 可能只用了 4 个就把收到的字节流交付上层的应用程序)。
同时,TCP 不关心应用进程一次把多长的报文发送到 TCP 的 缓存 中,而是根据对方给出的窗口值和当前网络阻塞的程度来决定一个报文段应包含多少个字节(UDP 发送的报文长度是应用进程给出的)。如果应用进程传送到 TCP 缓存的数据块太长,TCP 就可以把他划分短一点再传送。如果应用程序一次只发来一个字节,TCP 也可以等待积累有足够多的字节后再构成报文段发送出去。
TCP 发送报文一般是 3 个时机:
- 缓冲区数据达到 最大报文长度 MSS;
- 由发送端的应用进程指明要求发送报文段,即 TCP 支持的推送(push)操作;
- 当发送方的一个计时器期限到了,即使长度不超过 MSS ,也发送。
以上引自《计算机网络-----谢希仁》。
说了这么多,TCP 的这种机制,会导致什么问题呢?粘包问题。有了粘包,就需要拆包。
如何区分一个整包消息,业界通常有如下 4 种做法:
固定长度,例如每 120 个字节代表一个整包消息,不足的前面补零。解码器在处理这类定常消息的时候比较简单,每次读到指定长度的字节后再进行解码。
通过回车换行符区分消息,例如 FTP 协议。这类区分消息的方式多用于文本协议。
通过分隔符区分整包消息。
通过指定长度来标识整包消息。
Netty 作为一个网络框架,对 TCP 连接中的问题都做了全面的考虑,比如粘包拆包导致的半包问题,如何编解码,如何实现私有协议,序列化等等。本文主要针对这些问题做一个简单介绍,目的是想对整个 Netty 的编解码框架做一个全盘的审视,以确保在后面的源码学习中不会一叶障目不见泰山。
二、基于长度编解码器的具体实现
基于长度的实现有 2 个现成的类:
FixedLengthFrameDecoder基于构造函数中的固定长度。
该类很简单,构造方法中,传入一个整数,该解码器就会按照这个数字对累积区的字节进行切分。LengthFieldBasedFrameDecoder基于流中动态的长度
该类比较复杂。构造函数参数多达 6 个,在构建私有协议栈时大有用处。
三、基于分割符的编解码器
同样有 2 个:
DelimiterBasedFrameDecoder用户提供分割符。
该类比较简单,根据用户提供的分割符对累积区的内容进行分割。性能相对不是那么完美。LineBasedFrameDecoder基于换行符,支持多种换行符 \n \r\n 速度相比自定义较快。
该类使用更简单,根据换行符进行拆包粘包。
四、google 的 ProtobufDecoder ProtobufEncoder 序列化介绍
Netty 中有很多序列化工具,比如 Jboss 的 Marshalling,同时也支持 Java 标准的序列化。 但我们重点关注 google 的 protobuf 库。因为它的性能最高。
上面的 4 个解码器都是基于 ByteToMessageDecoder,将粘包的字节转为用户需要的字节。而 ProtobufDecoder 不是继承自 ByteToMessageDecoder,而是继承自 MessageToMessageDecoder,名字都不同。MessageToMessageDecoder 的作用是什么呢?
从名字上看,该类用于将两个消息进行转换(比如一种 POJO 转成另一种)。后面我们将花大篇幅讲述这个类库。
五、其他的
(1) TooLongFrameException
由于 Netty 是一个异步框架,所以需要在字节可以解码之前在内存中缓冲他们。因此不能让解码器缓冲大量的数据以至于耗尽可用的内存。为了解决这个问题,Netty 提供了 TooLongFrameException 类,其将由解码器在帧超出指定的大小限制时抛出异常。
你可以设置一个最大的阈值,当超过该阈值,这抛出异常。
(2) 写大型数据的 FileRegion
有时候你可能需要写一个大型的数据,如果不停的写入,可能导致 OOM,所以在写大型数据时,需要准备好处理到远程节点的连接时慢速连接的情况,这种情况会导致内存释放的延迟。
我们可以使用 NIO 的零拷贝特性,这种特性消除了将文件内容从文件系统移动到网络栈的复制过程。而我们所需要做的就是使用一个 FileRegion 接口的实现。
官方定义:
通过支持零拷贝的文件传输的 Channel 来发送的文件区域。
六、总结
本文并没有刨析源码,主要是针对 Netty 中现有的或者设计的编解码,序列化等工具做一个介绍,方便后面有条不紊的按照这个路线研究他们的具体实现。
参考:
- 《Netty 粘包 & 拆包 & 编码 & 解码 & 序列化 介绍》:http://www.cnblogs.com/stateis0/p/9062162.html
每天用心记录一点点。内容也许不重要,但习惯很重要!
Netty 源码 ChannelHandler(四)编解码技术的更多相关文章
- Netty 源码 ChannelHandler(三)概述
Netty 源码 ChannelHandler(三)概述 Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) 一.Channel ...
- 阿里P7终于讲完了JDK+Spring+mybatis+Dubbo+SpringMvc+Netty源码
前言 这里普及一下,每个公司都有职别定级系统,阿里也是,技术岗以 P 定级,一般校招 P5, 社招 P6 起.其实阅读源码也是有很多诀窍的,这里分享几点心得: 首先要会用.你要知道这个库是干什么的,掌 ...
- netty源码解解析(4.0)-18 ChannelHandler: codec--编解码框架
编解码框架和一些常用的实现位于io.netty.handler.codec包中. 编解码框架包含两部分:Byte流和特定类型数据之间的编解码,也叫序列化和反序列化.不类型数据之间的转换. 下图是编解码 ...
- Netty 编解码技术 数据通信和心跳监控案例
Netty 编解码技术 数据通信和心跳监控案例 多台服务器之间在进行跨进程服务调用时,需要使用特定的编解码技术,对需要进行网络传输的对象做编码和解码操作,以便完成远程调用.Netty提供了完善,易扩展 ...
- netty权威指南学习笔记六——编解码技术之MessagePack
编解码技术主要应用在网络传输中,将对象比如BOJO进行编解码以利于网络中进行传输.平常我们也会将编解码说成是序列化/反序列化 定义:当进行远程跨进程服务调用时,需要把被传输的java对象编码为字节数组 ...
- java编解码技术,netty nio
对于java提供的对象输入输出流ObjectInputStream与ObjectOutputStream,可以直接把java对象作为可存储 的字节数组写入文件,也可以传输到网络上去.对与java开放人 ...
- Netty编解码技术
编解码技术,说白了就是java序列化技术,序列化目的就两个,第一进行网络传输,第二对象持久化. 虽然我们可以使用java进行对象序列化,netty去传输,但是java序列化的硬伤比较多,比如java序 ...
- Netty 源码(ChannelHandler 死磕)
精进篇:netty源码死磕5 - 揭开 ChannelHandler 的神秘面纱 目录 1. 前言 2. Handler在经典Reactor中的角色 3. Handler在Netty中的坐标位置 4 ...
- ChannelHandler揭秘(Netty源码死磕5)
精进篇:netty源码死磕5 揭开 ChannelHandler 的神秘面纱 目录 1. 前言 2. Handler在经典Reactor中的角色 3. Handler在Netty中的坐标位置 4. ...
随机推荐
- mysql查看在线用户
有时候我们需要了解mysql数据库都有那些用户在线操作.我们可以用以下命令来查看当前在操作mysql的在线账户. show processlist;
- mongodb数据到MySQL数据库 的迁移步骤
废话少说,直接上干货. 1.mongoexport -d shengyang -c testData -f _id,x,name,name1,name2 --type=csv -o new.csv 用 ...
- ivew 表格中的input数据改变就会失去焦点
主要有两种解决办法: 1.创建一个临时空数组创建一个临时空数组,render内操作的是这个空数组内的对象,然后监听这个临时空数组,在赋值给table组件的data,render内操作的是这个空数组内的 ...
- beebase
1.简单介绍 BeeBase是一个在线生物信息学数据库,显示与Apis mellifera.欧洲蜜蜂以及一些病原体和其他物种有关的数据.它是与蜜蜂基因组测序联盟合作开发的.BeeBase是蜜蜂研究社区 ...
- ORACLE 如何产生一个随机数
1.select dbms_random.string('x', 3) from dual ; x是类型,3是长度. /* opt可取值如下: 'u','U' : 大写字母 'l','L' ...
- log4j最中意的配置
log4j.rootLogger=DEBUG, Console, logfile log4j.appender.Console=org.apache.log4j.ConsoleAppender log ...
- linux下安装kafka
安装条件: 确保zookeeper已经安装成功.zookeeper安装过程见:https://www.cnblogs.com/expiator/p/9853378.html 1.下载kafka 进入A ...
- python读写文件中read()、readline()和readlines()的用法
python中有三种读取文件的函数: read() readline() readlines() 然而它们的区别是什么呢,在平时用到时总会遇到,今天总结一下. 0. 前期工作 首先新建一个文件read ...
- 【Linux 线程】常用线程函数复习《一》
1.pthread_create以及pthread_self函数 /****************************************************************** ...
- Bootstrap(1) 概述与环境搭建
视频教程:http://study.163.com/course/courseMain.htm?courseId=1017002 源码和笔记:http://pan.baidu.com/s/1c06Ri ...