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 种做法:

  1. 固定长度,例如每 120 个字节代表一个整包消息,不足的前面补零。解码器在处理这类定常消息的时候比较简单,每次读到指定长度的字节后再进行解码。

  2. 通过回车换行符区分消息,例如 FTP 协议。这类区分消息的方式多用于文本协议。

  3. 通过分隔符区分整包消息。

  4. 通过指定长度来标识整包消息。

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 中现有的或者设计的编解码,序列化等工具做一个介绍,方便后面有条不紊的按照这个路线研究他们的具体实现。

参考:

  1. 《Netty 粘包 & 拆包 & 编码 & 解码 & 序列化 介绍》:http://www.cnblogs.com/stateis0/p/9062162.html

每天用心记录一点点。内容也许不重要,但习惯很重要!

Netty 源码 ChannelHandler(四)编解码技术的更多相关文章

  1. Netty 源码 ChannelHandler(三)概述

    Netty 源码 ChannelHandler(三)概述 Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) 一.Channel ...

  2. 阿里P7终于讲完了JDK+Spring+mybatis+Dubbo+SpringMvc+Netty源码

    前言 这里普及一下,每个公司都有职别定级系统,阿里也是,技术岗以 P 定级,一般校招 P5, 社招 P6 起.其实阅读源码也是有很多诀窍的,这里分享几点心得: 首先要会用.你要知道这个库是干什么的,掌 ...

  3. netty源码解解析(4.0)-18 ChannelHandler: codec--编解码框架

    编解码框架和一些常用的实现位于io.netty.handler.codec包中. 编解码框架包含两部分:Byte流和特定类型数据之间的编解码,也叫序列化和反序列化.不类型数据之间的转换. 下图是编解码 ...

  4. Netty 编解码技术 数据通信和心跳监控案例

    Netty 编解码技术 数据通信和心跳监控案例 多台服务器之间在进行跨进程服务调用时,需要使用特定的编解码技术,对需要进行网络传输的对象做编码和解码操作,以便完成远程调用.Netty提供了完善,易扩展 ...

  5. netty权威指南学习笔记六——编解码技术之MessagePack

    编解码技术主要应用在网络传输中,将对象比如BOJO进行编解码以利于网络中进行传输.平常我们也会将编解码说成是序列化/反序列化 定义:当进行远程跨进程服务调用时,需要把被传输的java对象编码为字节数组 ...

  6. java编解码技术,netty nio

    对于java提供的对象输入输出流ObjectInputStream与ObjectOutputStream,可以直接把java对象作为可存储 的字节数组写入文件,也可以传输到网络上去.对与java开放人 ...

  7. Netty编解码技术

    编解码技术,说白了就是java序列化技术,序列化目的就两个,第一进行网络传输,第二对象持久化. 虽然我们可以使用java进行对象序列化,netty去传输,但是java序列化的硬伤比较多,比如java序 ...

  8. Netty 源码(ChannelHandler 死磕)

    精进篇:netty源码死磕5  - 揭开 ChannelHandler 的神秘面纱 目录 1. 前言 2. Handler在经典Reactor中的角色 3. Handler在Netty中的坐标位置 4 ...

  9. ChannelHandler揭秘(Netty源码死磕5)

    精进篇:netty源码死磕5  揭开 ChannelHandler 的神秘面纱 目录 1. 前言 2. Handler在经典Reactor中的角色 3. Handler在Netty中的坐标位置 4. ...

随机推荐

  1. NCBI之gene系列

    1.基因系列中的data索引 2.基因ID之间的转换 对于生信,依托于别人的工具不如自己动手,由于研究发表的滞后性,往往很多工具提供的转换并不是最新的,况且开发者水平也参差不齐,理解原理才能让你来去自 ...

  2. 1.3.7、CDH 搭建Hadoop在安装之前(端口---第三方组件使用的端口)

    第三方组件使用的端口 在下表中,每个端口的“ 访问要求”列通常是“内部”或“外部”.在此上下文中,“内部”表示端口仅用于组件之间的通信; “外部”表示该端口可用于内部或外部通信. Component ...

  3. linux安装jdk以及tomcat

    一.卸载旧jdk 1.检测原OPENJDK版本 java -version 查看是否安装了jdk,并且是什么版本 2.进一步查看JDK信息 rpm -qa|grep java tzdata-java- ...

  4. java 字符串转16进制的方法

    方法一: 用java自带的方法 先将字符串转为字符数组,然后用Integer.toHexString方法进行转换. 缺点:中文容易乱码 方法二: 使用apache的包codec中的方法 org.apa ...

  5. 搭建jsp渗透测试环境

    java运行环境下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html fir ...

  6. Redis集群架构【转载】

    Redis 集群的 TCP 端口(Redis Cluster TCP ports) 每个 Redis 集群节点需要两个 TCP 连接打开.正常的 TCP 端口用来服务客户端,例如 6379,加 100 ...

  7. java学习笔记整理

    java知识模块:1.基础知识,数组,字符串,正则表达式:2.类和对象,接口,继承,多态,抽象类,内部类,泛型,java常用类库.3.异常处理: 4.IO:   5.事件处理:   6.多线程:  7 ...

  8. TZOJ 4848 货车运输(最大生成树+倍增lca)

    描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多 ...

  9. Django 改变xadmin后台英文为中文

    1.标题 setting.py文件: LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' 修改: LANGUAGE_CODE = 'zh-Hans' TIME_ZONE ...

  10. shell 脚本编写基础

    在进行Linux测试时编写脚本是必不可少的,Shell脚本的名称可以随便定义,也不要什么后缀名,例如可以写abc,smartzip这类名称,运行时只要键入 ./smartzip就能运行脚本了.. 每行 ...