Netty 粘包 & 拆包 & 编码 & 解码 & 序列化 介绍

目录:
- 粘包 & 拆包及解决方案 ByteToMessageDecoder
- 基于长度编解码器
- 基于分割符的编解码器
- google 的 Protobuf 序列化介绍
- 其他的
前言
Netty 作为一个网络框架,对 TCP 连接中的问题都做了全面的考虑,比如粘包拆包导致的半包问题,如何编解码,如何实现私有协议,序列化等等。本文主要针对这些问题做一个简单介绍,目的是想对整个 Netty 的编解码框架做一个全盘的审视,以确保在后面的源码学习中不会一叶障目不见泰山。
1. 粘包 & 拆包及解决方案 ByteToMessageDecoder
由于TCP是面向字节流的,什么意思呢:虽然应用程序和 TCP 的交互是一次一个数据块(大小不等),但 TCP 把应用程序交下来的数据仅仅看成式一连串的无结构的字节流。TCP 并不知道所传送的字节流的含义。
因此 TCP 不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系(例如,发送方应用程序交给发送方的 TCP 共 10 个数据块,但接收方的 TCP 可能只用了 4 个就把收到的字节流交付上层的应用程序)。
同时,TCP 不关心应用进程一次把多长的报文发送到 TCP 的 缓存 中,而是根据对方给出的窗口值和当前网络阻塞的程度来决定一个报文段应包含多少个字节(UDP 发送的报文长度是应用进程给出的)。如果应用进程传送到 TCP 缓存的数据块太长,TCP 就可以把他划分短一点再传送。如果应用程序一次只发来一个字节,TCP 也可以等待积累有足够多的字节后再构成报文段发送出去。
- TCP 发送报文一般是 3 个时机:
- 缓冲区数据达到
最大报文长度 MSS; - 由发送端的应用进程指明要求发送报文段,即 TCP 支持的推送(push)操作;
- 当发送方的一个计时器期限到了,即使长度不超过 MSS ,也发送。
以上引自《计算机网络-----谢希仁》。
说了这么多,TCP 的这种机制,会导致什么问题呢?粘包问题。有了粘包,就需要拆包。
- 一般解决粘包拆包问题有 4 种办法:
- 固定数据的长度,比如 100 字节,如果不够就补空格。
- 学习 HTTP ,FTP 等,使用回车换行符号。
- 将消息分为 head 和 body,head 中包含 body 长度的字段,一般 head 的第一个字段使用 int 值来表示 body 长度。
- 使用更复杂的应用层协议(等于没说 =_= !)。
Netty 作为一个网络框架,直接和 TCP 打交道,自然考虑了这个问题。而解决这个问题的主要实现就是抽象类 ByteToMessageDecoder,详见 Netty 解码器抽象父类 ByteToMessageDecoder 源码解析。Netty 使用了模板设计模式,这个类只定义了共有行为,具体解码实现还是子类,比如上面提到的 4 种方式。
2. 基于长度编解码器的具体实现
基于长度的实现有2个现成的类:
FixedLengthFrameDecoder 基于构造函数中的固定长度
该类很简单,构造方法中,传入一个整数,该解码器就会按照这个数字对累积区的字节进行切分。LengthFieldBasedFrameDecoder 基于流中动态的长度
该类比较复杂。构造函数参数多达 6 个,在构建私有协议栈时大有用处。
3. 基于分割符的编解码器
同样有 2 个:
DelimiterBasedFrameDecoder 用户提供分割符。
该类比较简单,根据用户提供的分割符对累积区的内容进行分割。性能相对不是那么完美。LineBasedFrameDecoder 基于换行符,支持多种换行符 \n \r\n 速度相比自定义较快。
该类使用更简单,根据换行符进行拆包粘包。
4. google 的 ProtobufDecoder ProtobufEncoder 序列化介绍
Netty 中有很多序列化工具,比如 Jboss 的 Marshalling,同时也支持 Java 标准的序列化。 但我们重点关注 google 的 protobuf 库。因为它的性能最高。
上面的 4 个解码器都是基于 ByteToMessageDecoder,将粘包的字节转为用户需要的字节。而ProtobufDecoder 不是继承自 ByteToMessageDecoder,而是继承自 MessageToMessageDecoder,名字都不同。MessageToMessageDecoder 的作用是什么呢?
从名字上看,该类用于将两个消息进行转换(比如一种 POJO 转成另一种)。后面我们将花大篇幅讲述这个类库。
5. 其他的
1. TooLongFrameException
由于 Netty 是一个异步框架,所以需要在字节可以解码之前在内存中缓冲他们。因此不能让解码器缓冲大量的数据以至于耗尽可用的内存。为了解决这个问题,Netty 提供了 TooLongFrameException 类,其将由解码器在帧超出指定的大小限制时抛出异常。
你可以设置一个最大的阈值,当超过该阈值,这抛出异常。
2. 写大型数据的 FileRegion
有时候你可能需要写一个大型的数据,如果不停的写入,可能导致 OOM,所以在写大型数据时,需要准备好处理到远程节点的连接时慢速连接的情况,这种情况会导致内存释放的延迟。
我们可以使用 NIO 的零拷贝特性,这种特性消除了将文件内容从文件系统移动到网络栈的复制过程。而我们所需要做的就是使用一个 FileRegion 接口的实现。
官方定义:
通过支持零拷贝的文件传输的 Channel 来发送的文件区域。
6. 总结
本文并没有刨析源码,主要是针对 Netty 中现有的或者设计的编解码,序列化等工具做一个介绍,方便后面有条不紊的按照这个路线研究他们的具体实现。
good luck!!!!
Netty 粘包 & 拆包 & 编码 & 解码 & 序列化 介绍的更多相关文章
- Netty 粘包 拆包 | 史上最全解读
Netty 粘包/半包原理与拆包实战(史上最全) 疯狂创客圈 Java 聊天程序[ 亿级流量]实战系列之13 [博客园 总入口 ] 本文的源码工程:Netty 粘包/半包原理与拆包实战 源码 本实例是 ...
- Netty 粘包/拆包应用案例及解决方案分析
熟悉TCP变成的可以知道,无论是客户端还是服务端,但我们读取或者发送消息的时候,都需要考虑TCP底层粘包/拆包机制,下面我们先看一下TCP 粘包/拆包和基础知识,然后模拟一个没有考虑TCP粘包/拆包导 ...
- 从零开始实现简单 RPC 框架 7:网络通信之自定义协议(粘包拆包、编解码)
当 RPC 框架使用 Netty 通信时,实际上是将数据转化成 ByteBuf 的方式进行传输. 那如何转化呢?可不可以把 请求参数 或者 响应结果 直接无脑序列化成 byte 数组发出去? 答:直接 ...
- java架构之路-(netty专题)netty的编解码(出入战)与粘包拆包
上次回归: 上次博客我们主要说了netty的基本使用,都是一些固定的模式去写的,我们只需要关注我们的拦截器怎么去写就可以了,然后我们用我们的基础示例,改造了一个简单的聊天室程序,可以看到内部加了一个S ...
- Netty 粘包/半包原理与拆包实战
Java NIO 粘包 拆包 (实战) - 史上最全解读 - 疯狂创客圈 - 博客园 https://www.cnblogs.com/crazymakercircle/p/9941658.html 本 ...
- TCP粘包/拆包 ByteBuf和channel 如果没有Netty? 传统的多线程服务器,这个也是Apache处理请求的模式
通俗地讲,Netty 能做什么? - 知乎 https://www.zhihu.com/question/24322387 谢邀.netty是一套在java NIO的基础上封装的便于用户开发网络应用程 ...
- 深入学习Netty(5)——Netty是如何解决TCP粘包/拆包问题的?
前言 学习Netty避免不了要去了解TCP粘包/拆包问题,熟悉各个编解码器是如何解决TCP粘包/拆包问题的,同时需要知道TCP粘包/拆包问题是怎么产生的. 在此博文前,可以先学习了解前几篇博文: 深入 ...
- 【转】Netty之解决TCP粘包拆包(自定义协议)
1.什么是粘包/拆包 一般所谓的TCP粘包是在一次接收数据不能完全地体现一个完整的消息数据.TCP通讯为何存在粘包呢?主要原因是TCP是以流的方式来处理数据,再加上网络上MTU的往往小于在应用处理的消 ...
- Netty之解决TCP粘包拆包(自定义协议)
1.什么是粘包/拆包 一般所谓的TCP粘包是在一次接收数据不能完全地体现一个完整的消息数据.TCP通讯为何存在粘包呢?主要原因是TCP是以流的方式来处理数据,再加上网络上MTU的往往小于在应用处理的消 ...
随机推荐
- 单个div充满屏幕的CSS方法
1.通过定位实现 <style> *{ margin: 0; padding: 0; } div{ width:100%; height: 100%; background: yellow ...
- pdo的简单介绍和使用
1,PDO的定义:php data object(php数据对象); 2,连接pdo的相关参数:$dsn.$user.$pass. 其中$dsn="mysql:host=$host;dbna ...
- @ResponseBody 返回乱码 的解决办法
1:最快的 最简单的办法是 在Ajax请求脸面指定头信息Accept属性,StringHttpMessageConverter默认iso-8859-1编码,但是会根据请求头信息指定的编码格式来转换 ...
- Fiddler工具使用介绍一
Fiddler基础知识 Fiddler是强大的抓包工具,它的原理是以web代理服务器的形式进行工作的,使用的代理地址是:127.0.0.1,端口默认为8888,我们也可以通过设置进行修改. 代理就是在 ...
- post上传和压缩、插件模拟请求
gzip gzip一种压缩方式,或者是文件形式,它主要用于网络传输数据的压缩 gzip压缩好不好用 浏览器:网速一定.内容越小.请求响应的速度是不是更快 手机server:返回数据类型是json/ ...
- ubuntu18.04LTS设置静态IP
ubuntu18.04LTS设置静态IP 因为Ubuntu18.04采用的是netplan来管理network.所以在/etc/netplan/目录下有一个以yaml结尾的文件.比如01-networ ...
- map,set和weakmap,weakset
概述 set和map属于es6的内容,今天在看书的时候遇到了,所以好好的总结一下,供以后开发时参考,相信对其他人也有用. 参考资料: mdn Keyed collections Map和WeakMap ...
- pycharm删除project
1 在pycharm里面选择关闭project 2 返回到这个页面,然后点×让project不在project列表显示(最好记住project的位置) 3 到源文件夹删除这个project文件夹 大功 ...
- 使用git在github上创建新工程
这段时间进经常会忘记如何在github上同步工程,于是又得查资料,查参考书,浪费了很长时间,因此有了感触,写几篇有关此类问题的篇章! 这是老手新手都十分容易犯的错误,就是在创建一个新github项目或 ...
- Ubuntu双网卡设置内外网上网的问题
UBUNTU16.04系统,双网卡:eth0, eth1.分贝设置成Public IP, 和局域网IP, 这样这台计算机就可以访问局域网内的各个IP, 同时还可以在全球各地被访问,使用ssh or r ...