Netty 必知必会(六)—— 粘包拆包问题

news2024/9/22 17:24:50
  • tcp粘包、半包怎么解决的(LineBased和LengthBased,我是用的是LineBased)
  • 为什么要使用LineBased,怎么分割的(/r/n,当时没有考虑太多,觉得这个比较简单)
  • Netty解决粘包的几种方式
  • Netty 拆包粘包的实质
  • 项目中如何解决粘包、拆包的问题(基于字符或者基于长度)
  • 你这个报文传输的时候会不会遇到报文粘连的情况?如何解决?
  • TCP 的粘包的概念是对的吗(面试官:TCP 是面向字节流的,所以这个概念本身是一个伪概念,本身就是可以粘的。但是这种现象还是要解决的)
  • 基于Netty实现通信,使用了哪些TCP优化参数?
  • 你说网络通信使用的Netty,你都通过那些设置对Netty进行过调优

一、TCP 粘包拆包问题

TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。

TCP 是以字节流的方式来处理数据,一个完整的包可能会被 TCP 拆分成多个包进行发送,也可能把小的封装成一个大的数据包发送。

TCP 中可能出现粘包/拆包的原因:

  • Socket 缓冲区与滑动窗口
  • MSS/MTU限制
  • Nagle算法

1.Socket缓冲区与滑动窗口

应用层在传输数据时,实际上会先将数据写入到 TCP Socket的缓冲区,当缓冲区被写满后,数据才会被写出去。每个TCP Socket 在内核中都有一个发送缓冲区(SO_SNDBUF )和一个接收缓冲区(SO_RCVBUF),TCP 的全双工的工作模式以及 TCP 的滑动窗口便是依赖于这两个独立的 buffer 以及此 buffer 的填充状态。

SO_SNDBUF:进程发送的数据的时候假设调用了一个 send 方法,将数据拷贝进入 Socket 的内核发送缓冲区之中,然后 send 便会在上层返回。

SO_RCVBUF:把接收到的数据缓存入内核,应用进程一直没有调用 read 进行读取的话,此数据会一直缓存在相应 Socket 的接收缓冲区内。

接收缓冲区保存收到的数据一直到应用进程读走为止。对于 TCP,如果应用进程一直没有读取,buffer 满了之后发生的动作是:通知对端 TCP 协议中的窗口关闭。这个便是滑动窗口的实现。

滑动窗口:TCP连接在三次握手的时候,会将自己的窗口大小(window size)发送给对方,其实就是 SO_RCVBUF 指定的值。

  • 发送方:之后在发送数据的时,发送方必须要先确认接收方的窗口没有被填充满,如果没有填满,则可以发送。每次发送数据后,发送方将自己维护的对方的 window size 减小,表示对方的 SO_RCVBUF 可用空间变小。
  • 接收方:当接收方处理开始处理 SO_RCVBUF 中的数据时,会将数据从 Socket 在内核中的接受缓冲区读出,此时接收方的 SO_RCVBUF 可用空间变大,即 window size 变大,接受方会以 ack 消息的方式将自己最新的 window size 返回给发送方,此时发送方将自己的维护的接受方的 window size 设置为ack消息返回的 window size。

此外,发送方可以连续的给接受方发送消息,只要保证对方的 SO_RCVBUF 空间可以缓存数据即可,即 window size>0。当接收方的 SO_RCVBUF 被填充满时,此时 window size=0,发送方不能再继续发送数据,要等待接收方 ack 消息,以获得最新可用的 window size。

SO_RCVBUF 和 SO_SNDBUF:通常建议值为 128K 或者 256K;

2.MSS/MTU分片

MTU (Maxitum Transmission Unit,最大传输单元) 是链路层对一次可以发送的最大数据的限制。MSS (Maxitum Segment Size,最大分段大小) 是 TCP 报文中 data 部分的最大长度,是传输层对一次可以发送的最大数据的限制。

数据在传输过程中,每经过一层,都会加上一些额外的信息:

  • 应用层:只关心发送的数据 data,将数据写入 Socket 在内核中的缓冲区 SO_SNDBUF 即返回,操作系统会将 SO_SNDBUF 中的数据取出来进行发送;
  • 传输层:会在 data 前面加上 TCP Header(20字节);
  • 网络层:会在 TCP 报文的基础上再添加一个 IP Header,也就是将自己的网络地址加入到报文中。IPv4 中 IP Header 长度是 20 字节,IPV6 中 IP Header 长度是 40 字节;
  • 链路层:加上 Datalink Header 和 CRC。会将 SMAC(Source Machine,数据发送方的MAC地址),DMAC(Destination Machine,数据接受方的MAC地址 )和 Type 域加入。SMAC+DMAC+Type+CRC 总长度为 18 字节;
  • 物理层:进行传输。

3.Nagle 算法

Nagle 算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。

Nagle 算法的基本定义是任意时刻,最多只能有一个未被确认的小段。 所谓 “小段”,指的是小于 MSS 尺寸的数据块;所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的 ACK 确认该数据已收到。

Nagle 算法的规则:

  1. 如果 SO_SNDBUF 中的数据长度达到 MSS,则允许发送;
  2. 如果该 SO_SNDBUF 中含有 FIN,表示请求关闭连接,则先将 SO_SNDBUF 中的剩余数据发送,再关闭;
  3. 设置了 TCP_NODELAY=true 选项,则允许发送。TCP_NODELAY 是取消 TCP 的确认延迟机制,相当于禁用了 Negle 算法。正常情况下,当 Server 端收到数据之后,它并不会马上向 client 端发送 ACK,而是会将 ACK 的发送延迟一段时间(一般是 40ms),它希望在 t 时间内 server 端会向 client 端发送应答数据,这样 ACK 就能够和应答数据一起发送,就像是应答数据捎带着 ACK 过去。当然,TCP 确认延迟 40ms 并不是一直不变的, TCP 连接的延迟确认时间一般初始化为最小值 40ms,随后根据连接的重传超时时间(RTO)、上次收到数据包与本次接收数据包的时间间隔等参数进行不断调整。另外可以通过设置 TCP_QUICKACK 选项来取消确认延迟;
  4. 未设置 TCP_CORK 选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;
  5. 上述条件都未满足,但发生了超时(一般为200ms),则立即发送。

基于以上问题,TCP层肯定是会出现当次接收到的数据是不完整数据的情况。

出现粘包(针对后面的数据包而言)可能的原因有:

  • 发送方每次写入数据 < Socket缓冲区大小;
  • 接收方读取Socket缓冲区数据不够及时。

出现半包(针对前面的数据包而言)的可能原因有:

  • 发送方每次写入数据 > Socket缓冲区大小;
  • 发送的数据大于协议 MTU,所以必须要拆包。

解决问题肯定不是在4层来做而是在应用层,通过定义通信协议来解决粘包和拆包的问题。

发送方 和 接收方约定某个规则:

  • 当发生粘包的时候通过某种约定来拆包;
  • 如果在拆包,通过某种约定来将数据组成一个完整的包处理。

二、Netty 解决办法

1. 定长协议

指定一个报文具有固定长度。比如约定一个报文的长度是 5 字节,那么:

报文:1234,只有4字节,但是还差一个怎么办呢,不足部分用空格补齐。就变为:1234 。

如果不补齐空格,那么就会读到下一个报文的字节来填充上一个报文直到补齐为止,这样粘包了。

定长协议的优点是使用简单,缺点很明显:浪费带宽。

Netty 中提供了 FixedLengthFrameDecoder ,支持把固定的长度的字节数当做一个完整的消息进行解码。

2. 特殊字符分割协议

很好理解,在每一个你认为是一个完整的包的尾部添加指定的特殊字符,比如:\n,\r等等。

需要注意的是:约定的特殊字符要保证唯一性,不能出现在报文的正文中,否则就将正文一分为二了。

Netty 中提供了 DelimiterBasedFrameDecoder 根据特殊字符进行解码,LineBasedFrameDecoder默认以换行符作为分隔符。

3. 变长协议

变长协议的核心就是:将消息分为消息头和消息体,消息头中标识当前完整的消息体长度。

发送方在发送数据之前先获取数据的二进制字节大小,然后在消息体前面添加消息大小;
接收方在解析消息时先获取消息大小,之后必须读到该大小的字节数才认为是完整的消息。

Netty 中提供了 LengthFieldBasedFrameDecoder ,通过LengthFieldPrepender 来给实际的消息体添加 length 字段。

总结 Netty 自带解决方式:

  • 消息定长:FixedLengthFrameDecoder 类

  • 包尾增加特殊字符分割:

    • 行分隔符类:LineBasedFrameDecoder
    • 自定义分隔符类 :DelimiterBasedFrameDecoder
  • 将消息分为消息头和消息体:LengthFieldBasedFrameDecoder 类。分为有头部的拆包与粘包、长度字段在前且有头部的拆包与粘包、多扩展头部的拆包与粘包。

在Netty中,通过使用合适的解码器(如定长解码器、换行符解码器、分隔符解码器和长度字段解码器)可以有效解决粘包和拆包问题。同时,结合TCP的重传机制和应用层的重传策略,可以有效地减少丢包现象,确保数据传输的可靠性。

合理设置 TCP 参数在某些场景下对于性能的提升可以起到显著的效果。

三、参考

Netty 中的粘包和拆包详解_netty拆包粘包-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1972263.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SD-WAN组网加速ZOOM视频会议

随着远程办公和在线教育的普及&#xff0c;视频会议已成为人们日常沟通的重要工具。然而&#xff0c;网络不稳定、延迟高和带宽不足等问题常常影响ZOOM视频会议的体验。为了有效解决这些问题&#xff0c;SD-WAN组网开始被应用于ZOOM视频会议加速。 那么&#xff0c;SD-WAN具体是…

西门子DNC 程序传输

西门子的 840DSL 828D Siemens ONE DNC程序传输大概可以有几种方式实现&#xff1a; 1.FTP方式 缺点&#xff1a;每台设备都需要开通授权 优点&#xff1a;设置简单 2.共享文件夹 缺点&#xff1a;如果上位机联网容易中病毒 优点&#xff1a;免费 3.直接传送程序文件到NCU 缺…

图书管理系统初实现

目录 实现过程&#xff1a; 运行结果&#xff1a; 从三个模块来实现图书管理系统&#xff1a;书本、用户、实现的功能 实现过程&#xff1a; 首先在Book包下定义一个book类&#xff0c;包含书名、作者、价格、类型、是否借出成员变量。 这些成员变量都是私有的&#xff0c;…

算法第十六天:leetcode349.两个数组的交集

一、两个数组的交集的题目描述与链接 349.两个数组的交集如下表所示&#xff0c;您可以直接复制下面网址进入力扣学习&#xff0c;在观看下面的内容之前您一定要先做一遍哦&#xff0c;以便让你印象更加深刻&#xff01; https://leetcode.cn/problems/intersection-of-two-a…

Unity强化工程 之 音效

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正 首先&#xff0c;音频这块组件较少&#xff0c;但是内容很重要&#xff0c;因为对于任何一款非特殊面向人群的游戏来说&a…

【人工智能】边缘计算与 AI:实时智能的未来

&#x1f48e; 我的主页&#xff1a;2的n次方_ &#x1f48e;1. 引言 随着物联网设备数量的爆炸性增长和对实时处理需求的增加&#xff0c;边缘计算与人工智能&#xff08;Edge AI&#xff09;成为一个热门话题。Edge AI 通过在本地设备上运行 AI 算法&#xff0c;减少对云计…

【秋招笔试】24-07-27-OPPO-秋招笔试题(算法岗)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 编程一对一辅导 ✨ 本系列打算持续跟新 秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 💡 第一题贪心模拟…

月木学途开发 3.2安装Nacos

安装jdk 查看jdk是否安装 java -version 下载网址&#xff1a;https://www.oracle.com/java/technologies/downloads/?er221886 下载命令&#xff1a; wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz 解压&#xff1a; tar -zxvf jdk-17_…

【OpenCV C++20 学习笔记】imgproc模块-绘图基础

imgproc模块-绘图基础 Point和Scalar类型Point类型Scalar类型 绘图操作创建图片对象和显示窗口绘制椭圆绘制圆绘制多边形绘制矩形画线 完整代码 Point和Scalar类型 Point类型 该类型表示一个2D的点&#xff0c;其坐标由图像中的 x x x和 y y y坐标确定。可以这样定义一个Poin…

如何基于欧拉系统完成数据库的安装

一、安装 当我们直接进行安装软件包时&#xff0c;会提示有冲突&#xff0c;此时&#xff0c;我们应该这样来解决 使用rpm命令 [rootlocalhost yum.repos.d]# rpm -qa | grep selinux使用 rpm命令卸载以下两个软件包 [rootlocalhost yum.repos.d]# rpm -e selinux-policy-3…

B站安全开发流程落地实践

一. 什么是安全开发生命周期&#xff08;SDL&#xff09; 1.1 SDL诞生背景 随着互联网技术的快速发展&#xff0c;网络系统及应用在给人们的生活带来巨大便利的同时&#xff0c;信息安全问题也逐渐成为用户和企业关注的焦点。然而&#xff0c;安全问题的管理和解决需要一个系统…

TCP半关闭过程

TCP半关闭过程 简介 tcp半关闭是指在一端发送完数据后&#xff0c;关闭发送通道&#xff0c;而保持接收通道继续接收数据。 过程 这里设序号为Seqx&#xff0c;确认号为Acky 客户端&#xff08;也可以是服务端发起&#xff09;发送 [FIN&#xff0c;ACK] 报文段&#xff0…

【已解决】树莓派5使用VNC远程,无法正常显示桌面,黑屏提示:cannot currently show the desktop

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

外贸干货|业务员寻找客户的7个思维技巧,都掌握的才算合格

更多外贸干货及开发客户的方法&#xff0c;尽在微信【千千外贸干货】 做外贸最基本的是找到客户&#xff0c;如果没有完成这一步&#xff0c;纵使你有千万种转化客户的方法&#xff0c;也都只是纸上谈兵。 #一 关键词法 选择适当的关键词&#xff0c;直接查找潜在客户发布的求…

Manim实现在坐标轴上添加元素和获取元素

Manim实现在坐标轴上添加元素和获取元素 1.坐标轴上获取元素 构造函数&#xff1a; _get_axis_label(label, axis, edge, direction, buff0.1) 函数 _get_axis_label 旨在为图形表示中的给定轴生成和定位标签&#xff08;通常用于绘图或数学上下文中&#xff0c;可能是在某…

PostgreSQL 15

一、安装前的准备 1、版本信息 操作系统CentOS 7.9.2009PostgreSQL 版本PostgreSQL 15-15.7 2、下载安装包 RPM Chart - PostgreSQL YUM Repositoryhttps://yum.postgresql.org/rpmchart/进入官网&#xff0c;找到相应版本 点击框选内容 依次进入下载页面&#xff0c;下载相…

ASUS/华硕幻15 2020 冰刃4 GX502L GU502L系列 原厂win10系统 工厂文件 带F12 ASUS Recovery恢复

华硕工厂文件恢复系统 &#xff0c;安装结束后带隐藏分区&#xff0c;一键恢复&#xff0c;以及机器所有驱动软件。 系统版本&#xff1a;windows10 原厂系统下载网址&#xff1a;http://www.bioxt.cn 需准备一个20G以上u盘进行恢复 请注意&#xff1a;仅支持以上型号专用…

免费好用的 CI/CD 工具有哪些?

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 更多关于极狐GitLab &a…

V.PS日本东京VPS详细测评

V.PS日本VPS怎么样&#xff1f;V.PS日本机房怎么样&#xff1f; V.PS在日本有东京和大阪两个机房都在运作VPS/云服务器&#xff0c;大阪机房的默认接入IIJ网络&#xff0c;日本东京机房的是日本软银网络&#xff0c;另外日本东京分两个系列&#xff0c;一个是Intel另外一个是AM…

【文件fd】深入理解重定向和缓冲区

目录 1.重定向 1.1dup2 2.缓冲区 2.1什么是缓冲区 2.2为什么存在缓冲区 2.3缓冲区的刷新策略 2.4查看源码​ 3.0/1/2 3.1 0/1/2是什么&为什么存在 3.2 2和1区别 3.3 2为什么存在 1.重定向 重定向的本质&#xff1a;是在内核中改变文件描述符表特定下标的内容和…