【计算机网络】TCP协议——3. 可靠性策略效率策略

 前言

TCP是一种可靠的协议,提供了多种策略来确保数据的可靠性传输。

可靠并不是保证每次发送的数据,对方都一定收到;而是尽最大可能让数据送达目的主机,即使丢包也可以知道丢包。

目录

一. 确认应答和捎带应答机制

二. 超时重传

超时时间

三. 滑动窗口

1. 滑动窗口的实现

2. 滑动窗口的相关问题(快重传) 

3. 延迟应答

四. 流量控制

五. 拥塞控制

六. 面向字节流&粘包问题

TCP小结

结束语


一. 确认应答和捎带应答机制

在上篇博客说到,TCP将每个字节的数据都进行了编号,即为序列号。

序列号,既是TCP面向字节流的体现,也对发送的数据进行了排序,即编号小的,一定是先发送的。接收方在收到TCP报文后,根据报头中的序列号,将TCP报文按照序号顺序放入接收缓冲区

TCP协议规定,接收方接收数据,必须发送确认报文。这就是确认应答

序列号和确认号就是TCP缓冲区的编号(下标)

  • 序列号:表示本报文第一个字节的编号(在缓冲区的下标)。在TCP连接中,所传输的字节流的每一个字节都会按顺序编号
  • 确认号:在客户服务器模式中,当发送方给接收方发送数据,接收方只要接收到数据,必须给发送方发送确认报文。此时报文中的确认号,表示接收方期望收到发送方下一个报文的第一个字节的编号,相当于告诉发送方,这个序号之前的报文我都收到了。接收方收到数据后,根据序号给出确认序号,发送给发送方,发送方就知道接收方收到了哪些数据。确认号通常和序列号搭配使用。如下图

确认应答是一种特殊的报文(ACK),所谓应答报文,本质是ACK标志位字段为1的报文,此时“确认序号”字段才生效

初始序号是随机的,为了防止网络攻击;如果发送多个数据,每个数据都会带着一个序号。

和确认应答搭配使用的是捎带应答,即一方返回确认应答ACK报文时,也可以携带要发送给对方的数据。

比如客户端给服务器发送“How are you?”,接收方收到数据后,发送ACK确认报文,同时可以在报文中附上有效载荷(数据):“Fine,thank you”。


确认应答不仅让发送方知晓哪些报文收到了,还可以提高双方通信的效率

上图线性的通信效率较低,确认应答可以让双方一次性发送多个报文

发送方一次发送多个报文,接收方一次性接收并发送多个确认应答

即使中间的确认应答丢失:比如2001的确认应答丢失,但发送方只要接收到4001的确认应答,就代表4001前的报文,接收方都收到了;若1001~2000的报文丢失,那么接收方即使收到了后面的额2001~3000的报文,也只会给发送方返回1001的确认应答,如此发送方也能知晓1001~2000的报文丢失,进而使用接下来的策略——超时重传

二. 超时重传

确认应答是比较理想的情况,数据在网络传输中,是可能会丢包的。

报文如果成功送达接收方,接收方会发送确认报文,发送方就知道报文成功送达。但也可能出现如下两种情况:

  • 发送方的报文丢失
  • 接受方的确认报文丢失

这两种情况,发送方都不会收到接收方的确认报文。

TCP规定,在报文发送后的一个时间间隔后,如果还没收到确认报文,发送方一律认为报文丢失,重新发送该报文,这就是超时重传。

也有可能报文或确认报文因为网络拥塞而延迟送达对方主机,此时发送方也会超时重传,因此主机B会收到很多重复数据,那么TCP协议需要能够识别出哪些报文是重复的,并把重复的报文丢弃——根据报文的序列号就可以知道哪些报文是重复的

超时时间

超时时间如何确定呢?

  • 最理想的情况下,找到一个最小的时间,保证“确认应答一定能在这个时间内返回”
  • 但是这个时间的长短,随着网络环境的不同,是有差异的。
  • 如果超时时间设置太长,会影响整体的重传效率
  • 如果超时时间设置太短,可能会频繁发送重复的报文

TCP为了保证在任何环境下都能有比较高性能的通信,因此会动态计算这个最大超时时间

  • Linux中(BSD Unix和Windows也是如此),超时以500ms为一个单位进行控制,每次判定超时重传的超时时间都是500ms的整数倍
  • 如果重发一次之后,仍得不到应答,等待2*500ms后再进行重传
  • 如果仍得不到应答,等待4*500ms进行重传,以此类推,以指数形式递增
  • 累计到一定的重传次数,TCP认为网络或者对端主机出现异常,强制关闭连接

三. 滑动窗口

上述我们了解到,发送方可以一次性发送多个报文,那么报文数量是如何确定的呢?

在TCP报文中,有一个16位窗口大小,该字段反应了发送该报文的主机进程的接收缓冲区剩余大小,即接收能力。

在通信双方建立连接,进行三次握手时,就会通报对方自己的窗口大小——即接收能力,双方基于每次通信报文中的窗口大小,动态的调整自己将要发送给对方的报文数量。这就是滑动窗口的原理


1. 滑动窗口的实现

在发送缓冲区中,有编号,即序列号的存在。滑动窗口是根据对端发送的窗口大小,将发送缓冲区划分成三部分。

 滑动窗口就是可发送,未收到应答的部分。

  • 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值,上图的窗口大小就是4000字节(四个段)
  • 发送滑动窗口内的四个分段时,不需要等待任何ACK,直接发送。原先发送1~1000,要等待1001的确认报文,才能发送1001~2000。但在滑动窗口范围内的报文,可以不用收到ACK,直接发送。
  • 收到一个ACK后,滑动窗口向后移动,继续发送第五个段的数据,以此类推

  • 操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉(被后续数据覆盖)
  • 窗口越大,则网络的吞吐率越高

代码实现上

操作系统可以维护两个变量——win_start和win_end,表示滑动窗口开始的序号和结束的序号

在收到一个确认报文后,确认报文中的seq确认序号,指示发送方下一次发送的序号,窗口大小(win)指示滑动窗口的大小(目前)

2. 滑动窗口的相关问题(快重传) 

问题1:滑动窗口只能向右滑动吗?向左可以吗?

回答:只能向右。因为滑动窗口将发送缓冲区划分为三个部分,左边部分是已经发送的数据且受到应答,不应该再发送。


问题2:滑动窗口能变大吗?能变小吗?能变0吗,表示什么意思?

回答:滑动窗口的大小取决于对方通告的win大小,即窗口大小(目前),当然可以变大或变小。变0表示对方暂时不能接受数据,可能是接收缓冲区已满


问题3:滑动窗口能一直向右滑动吗?不会越界?

回答:发送缓冲区被设计成环形队列,所以可以一直向右滑动,滑动窗口左边的部分,也会在后续被新的数据覆盖


问题4:出现丢包问题,如何进行重传?

这里分两种情况讨论:

情况一:数据包到达对方数据,ACK确认报文丢失

此时,部分ACK丢失不要紧,因为可以通过后续的ACK进行确认。

即使ACK=2001的确认报文丢失,但发送方收到ACK=5001的确认报文,这就代表接收方5001前的报文都已收到

情况二:数据包丢失

 

  • 当某一段报文丢失后,发送方会一直收到1001这样的ACK。
  • 如果发送端主机连续三次收到同样一个“ACK=1001”这样的确认报文,就会立刻将1001~2000的报文重新发送
  • 此时,接收端收到1001~2000的报文后,再次返回的确认报文ACK=7001(7001前的报文全部收到)

这种机制被称为“高速重发机制”,也叫快重传

3. 延迟应答

如果接收数据的主机立刻返回ACK,此时返回的窗口可能比较小

  • 假设接收方缓冲区为1M,一次收到500K的数据,如果立刻应答,返回的窗口大小就是500K
  • 但实际上上层可能处理速度很快,10ms之内就把500K的数据从缓冲区消费掉了
  • 在这种情况,接收端还远远没有达到自己的极限,即使发送数据再多些也能处理过来
  • 所以如果接收端能稍等一会应答,可能可以返回更大的窗口大小

窗口越大,网络吞吐量越大,传输效率越高。

延迟应答一般有如下限制:

  • 数量限制:每隔N个包就应答一次
  • 时间限制:超过最大延迟时间就应答一次

具体数量和超时时间,不同操作系统各有不同,一般N取2,超时时间为200ms

四. 流量控制

接收端处理数据的速度是有限的,如果发送端发的太快,导致接收端的缓冲区被打满,此时如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应

因此TCP支持根据接收端的接受能力,来决定发送端的发送速度,这个机制就叫做“流量控制(Flow Control)”

  • 接收端将自己可以接受的缓冲区大小放入TCP首部中的“窗口大小”字段,通过ACK端通知发送端;
  • 窗口大小字段越大,网络的吞吐率越高
  • 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端
  • 发送端接收这个窗口大小后,减慢自己的发送速度
  • 如果接收缓冲区满了,就会将窗口设置为0;此时发送方不再发送数据,但是需要定期发送一个窗口探测报文,知晓接收方的窗口大小

窗口字段为16位,最大表示65535字节,但其实窗口大小还可以更大

在TCP首部的选项字段,有一个窗口扩大因子M,实际窗口大小是,窗口字段的值左移M位,即2^(16+M) 字节

详细可参看:【计算机网络】TCP协议报头详解

五. 拥塞控制

滑动窗口既体现了TCP的可靠性,又提高了性能。但网络通信还需要考虑网络拥塞情况,所以TCP还需要拥塞控制。

网络中有很多主机,如果当前网络状态比较拥堵,在不清楚当前网络状态下,盲目根据接收方窗口大小发送数据,可能导致网络更为拥堵。

TCP引入慢启动机制——先发送少量数据,探测网络信道状态,了解当前网络拥堵情况,再决定按照多大的速度传输数据

此处引入一个概念——拥塞窗口,其大小为swnd

慢开始的思路是

  • 刚开始将cwnd设置成为一个MSS的数值,每经过一个传输轮次cwnd就加倍传输轮次:拥塞窗口所允许的发送的报文都连续发出去,且收到了对已发送的最后一个字节的确认
  • 因为是加倍(指数)增长,为了防止增长过度,引起网络阻塞,还设置一个慢开始门限(阈值)ssthresh。当cwnd超过ssthresh时,就改为拥塞避免算法,也就是线性缓慢增长
  • 当TCP开始启动时,慢启动阈值等于窗口最大值
  • 在每次超时重传后,慢启动阈值会变成检测到网络拥塞时的窗口大小的一半,同时将拥塞窗口cwnd设置为1

少量的丢包,触发超时重传;大量的丢包,认为是网络拥塞。当TCP通信开始后,网络吞吐量会逐渐上升,随着网络发生拥堵,吞吐量会立刻下降


注意:发送方的发送窗口,会根据接收方反馈的接收窗口和自身维护的拥塞窗口,取较小值作为实际发送的窗口大小

六. 面向字节流&粘包问题

面向字节流

创建一个TCP的socket,同时在内核中创建一个发送缓冲区和接收缓冲区

  • 调用write,数据会先写入发送缓冲区
  • 如果发送的数据太长,会被拆分成多个TCP数据包
  • 如果发送的字节数太短,就会先在缓冲区里等待,等到缓冲区长度差不多,或者其他合适的时机发出
  • 接收数据时,数据也是从网卡驱动程序到达内核的接收缓冲区
  • 然后应用程序可以调用read从接收缓冲区拿数据
  • 另一方面,TCP的一个连接,既有发送缓冲区,也有接收缓冲区。可以同时读写数据,这个概念叫做全双工

由于缓冲区的存在,TCP程序的读和写不需要一一匹配。

  • 写100个字节数据时,可以调用一次write写100个字节,也可以调用100次write,每次写一个字节;
  • 读100个字节数据时,也完全不需要考虑写的时候是怎么写的,既可以一次read 100个字节,也可以一次read一个字节,重复100次;

粘包问题

粘包问题中的"包" ,指的是应用层的数据包。在TCP的协议头中,没有如同UDP一样的"报文长度"这样的字段,但是有一个序号这样的字段。

  • 站在传输层的角度, TCP是一个一个报文过来的.按照序号排好序放在缓冲区中。
  • 站在应用层的角度,看到的只是一串连续的字节数据。那么应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始到哪个部分,是一个完整的应用层数据包。

不同数据粘连,就是粘包问题

明确两个包之间的边界,是避免粘包问题的根本:

  • 对于定长的包,保证每次都按固定大小读取即可;
  • 对于变长的包,可以在包头的位置,约定一个包总长度的字段,从而就知道了包的结束位置;
  • 对于变长的包,还可以在包和包之间使用明确的分隔符(应用层协议,是程序猿自己来定的,只要保证分隔符不和正文冲突即可);

注意:对于UDP协议,不存在粘包问题,因为UDP报头中有总长度,并且UDP是面向数据报的,有明确的数据边界。站在应用层的角度,使用UDP时,要么收到完整的UDP报文,要么不收,不会出现“半个报文”的情况

TCP小结

TCP协议可靠性机制有:

  • 校验和
  • 序列号(按序到达)
  • 确认应答
  • 超时重传
  • 连接管理
  • 流量控制
  • 拥塞控制

提高性能:

  • 滑动窗口
  • 快重传
  • 延迟应答
  • 捎带应答

其他:

定时器(超时重传定时器,保活定时器(连接),TIME_WAIT定时器等)

保活计时器和TIME_WAIT计时器可参看:【计算机网络】连接管理(三次握手,四次挥手)


基于TCP的应用层协议:HTTP,HTTPS,SSH,Telnet,FTP,SMTP。

结束语

本篇博客到此结束,感谢看到此处。
欢迎大家纠错和补充
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

什么是关键词排名蚂蚁SEO

关键词排名是指通过搜索引擎优化(SEO)技术,将特定的关键词与网站相关联,从而提高网站在搜索引擎中的排名。关键词排名对于网站的流量和用户转化率具有至关重要的影响,因此它是SEO工作中最核心的部分之一。 如何联系蚂…

机器学习 | SVM支持向量机

欲穷千里目,更上一层楼。 一个空间的混乱在更高维度的空间往往意味着秩序。 Machine-Learning: 《机器学习必修课:经典算法与Python实战》配套代码 - Gitee.com 1、核心思想及原理 针对线性模型中分类两类点的直线如何确定。这是一个ill-posed problem。…

【工作流Activiti】Activiti的使用

1、数据库支持 Activiti 运行必须要有数据库的支持&#xff0c;支持的数据库有&#xff1a;mysql、oracle、postgres、mssql、db2、h2 2、Activiti环境 我们直接在当前项目&#xff1a;guigu-oa-parent做Activiti入门讲解 2.1、引入依赖 <!--引入activiti的springboot启动…

苹果个人开发者如何实现应用下载安装

作为苹果个人开发者&#xff0c;你可以为iOS设备用户提供应用程序&#xff0c;而用户将能够通过下载和安装这些应用来丰富他们的设备体验。本文将详细介绍个人开发者实现应用下载安装的步骤&#xff0c;包括开发和上架应用程序到App Store。 图片来源&#xff1a;苹果个人开发者…

P2P应用

目录 一.P2P的简介 二.P2P的工作方式 1.具有集中目录服务器的P2P工作方式 2.具有全分布式结构的P2P文件共享程序 一.P2P的简介 P2P(对等连接)&#xff0c;是指两台主机在通信时&#xff0c;并不区分哪一个是服务请求方和哪一个是服务提供方。只要两台主机都运行了对等连接…

【06】GeoScene海图或者电子航道图数据自动化质检

1 S-58错误管理器验证产品 在你编辑数据时进行快速的质量检查可以使用S-58错误管理器&#xff0c;S-58错误管理器工具允许您使用IHO S-58验证标准来验证海事数据库中的产品。你可以验证整个产品&#xff0c;或验证产品的当前范围。 1.1验证产品 使用S-58错误管理器工具完成以…

Android vs. iOS:移动操作系统的对决

导言 Android和iOS作为两大主流移动操作系统&#xff0c;影响着数十亿用户的数字生活。Android和iOS&#xff0c;作为移动操作系统的巅峰代表&#xff0c;它们的竞争塑造了全球数十亿用户的数字化生活。本文将深入探讨这两个系统的起源、特点以及它们在用户体验、开发者生态和市…

Linux 特殊符号

目录 1. # 注释 2. &#xff1b;命令分隔符 3. .. 上级目录 4. . 当前目录 5. " " 换行&#xff0c;解析变量 6. 换行&#xff0c;不解析变量 7. \ 和 / 8. &#xff01;历史命令调用&#xff0c;取反 9. * 通配符 10. $ 调用变量 11. | 管道 12. || …

云原生之深入解析减少Docker镜像大小的优化技巧

一、什么是 Docker&#xff1f; Docker 是一种容器引擎&#xff0c;可以在容器内运行一段代码&#xff0c;Docker 镜像是在任何地方运行应用程序而无需担心应用程序依赖性的方式。要构建镜像&#xff0c;docker 使用一个名为 Dockerfile 的文件&#xff0c;Dockerfile 是一个包…

【二分查找】【z型搜索】LeetCode240:搜索二维矩阵

LeetCoe240搜索矩阵 作者推荐 【贪心算法】【中位贪心】.执行操作使频率分数最大 本文涉及的基础知识点 二分查找算法合集 题目 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。 每列的…

Vue 项目中使用 debugger 在 chrome 谷歌浏览器中失效以及 console.log 指向去了 vue.js 代码

问题 今天在代码里面输出 console.log 信息直接指向了 vue.js&#xff0c;并且代码里面写了 debgger 也不生效 解决 f12 找到浏览器的这个设置图标 找到这个 ignore list 的 custom exclusion rules 取消掉 /node_modules/|/bower_components/ 这样就正常了

【图神经网络】社区检测

社区检测 社区是许多网络的特性&#xff0c;一个特定的网络可能有多个社区&#xff0c;社区内的节点之间连接紧密。 网络节点在社区内部形成紧密的连接&#xff0c;而在社区之间则形成松散连接。 社区检测技术对于社交媒体算法来说非常有用&#xff0c;可以发现具有共同兴趣…

TrustZone之顶层软件架构

在处理器中的TrustZone和系统架构中,我们探讨了硬件中的TrustZone支持,包括Arm处理器和更广泛的内存系统。本主题关注TrustZone系统中发现的软件架构。 一、顶层软件架构 下图显示了启用TrustZone的系统的典型软件栈: 【注意】:为简单起见,该图不包括管理程序,尽管它们可…

sqlserver dba日常操作

查询慢sql的方法 1.whoisactive 安装方法 http://whoisactive.com/downloads/下载地址 将下载好的zip包放到sqlserver服务器中 文件-打开-文件-下载好的zip包-在查询窗口点击执行 新建一个查询窗口&#xff0c;输入sp_whoisactive&#xff0c;获取当前运行的所有sql语句 使用…

【计算机网络】TCP协议——2.连接管理(三次握手,四次挥手)

目录 前言 一. 建立连接——三次握手 1. 三次握手过程描述 2. TCP连接建立相关问题 二. 释放连接——四次挥手 1. 四次挥手过程描述 2. TCP连接释放相关问题 三. TCP状态转换 结束语 前言 TCP——传输控制协议(Transmission Control Protocol)。是一种面向连接的传…

Android 性能优化一篇解决

前言 使用java编写的源代码编译后生成了对于的class文件&#xff0c;但是class文件是一个非常标准的文件&#xff0c;市面上很多软件都可以对class文件进行反编译&#xff0c;为了我们app的安全性&#xff0c;就需要使用到Android代码混淆这一功能。针对 Java 的混淆&#xff…

不同版本QT使用qmake时创建QML项目的区别

不同版本QT使用qmake时创建QML项目的区别 文章目录 不同版本QT使用qmake时创建QML项目的区别一、QT5新建QML项目1.1 目录结构1.2 .pro 文件内容1.3 main.cpp1.4 main.qml 二、QT6新建QML项目2.1 目录结构2.2 .pro文件内容2.3 main.cpp2.4 main.qml 三、两个版本使用资源文件的区…

DSO在Euroc上运行经验贴,关于时间戳为0的结局方法

网上DSO基本上都是在TUM数据集上跑得&#xff0c;教程也比较多&#xff0c;写论文需要&#xff0c;使用DSO跑了一下Euroc数据集&#xff0c;踩了很多坑&#xff0c;花了一天的时间才调通&#xff0c;记录一下。 本机运行环境&#xff1a;Ubuntu16.04 其它环境只要安装过ORB-SA…

10.鸿蒙应用程序app创建第一个程序Helloworld

鸿蒙应用程序开发app_hap开发环境搭建 1.打开DevEco 2.创建项目 3.选择Empty Ability 4. 选择API6,支持java开发 5.点击Finish 6.启动本地模拟器参考方法 7.启动成功 8.运行程序 9.运行成功 其它文章点击专栏

龙芯loongarch64服务器编译安装gcc-8.3.0

前言 当前电脑的gcc版本为8.3.0,但是在编译其他依赖包的时候,出现各种奇怪的问题,会莫名其妙的中断编译。本地文章讲解如何自编译安装gcc,替换系统自带的gcc。 环境准备 下载页面:龙芯开源社区网站 - LoongArch GCC 8.3 交叉工具链 - 源码下载源码包名称如:loongson-gnu…
最新文章