TCP 重传机制 滑动窗口 流量控制 拥塞控制 学习总结!

大家好,我是三叔,很高兴这期又和大家见面了,一个奋斗在互联网的打工人。

这篇博客主要记录 tcp 的基础知识的学习总结相关内容!备注:图片均来自作者:小林哥

tcp 的三大特性

tcp 大家都不陌生,它的三大特性是:面向连接、可靠的、字节流的传输层通信协议。

  1. 面向连接:一定是一对一才能连接,经历三次握手建立的连接。(UDP 是可以一对多的)

  2. 可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端(TCP 是通过序列号、确认应答、重发控制、连接管理以及窗口控制等机制实现可靠性传输的。)

  3. 字节流:用户消息通过 TCP 协议传输时,消息可能会被操作系统分组成多个的 TCP 报文,如果接收方的程序如果不知道消息的边界,是无法读出一个有效的用户消息的。并且 TCP 报文是有序的,当前一个TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理,同时对重复的 TCP 报文会自动丢弃。

这里给大家展示一下TCP/IP 协议下的四层网络模型结构图,便于大家理解:(图片来源于网络)
在这里插入图片描述

重传机制

TCP 实现可靠传输的方式之一,是通过序列号与确认应答。

如图所示:这是一个正常的数据传输

在这里插入图片描述
但是在实际的网络环境中,消息的传输并不是总是一帆风顺的,万一在传输的过程中,发生数据丢失怎么办?所以 TCP 为了保证数据的可靠性,必须采取一些可靠的措施,针对数据丢包,进行一些重传机制。

例如:

  1. 超时重传
  2. 快速重传
  3. SACK
  4. D-SACK

超时重传

字面意思,很好理解,超过一定的时间,还没收到返回的信息,就会触发一个重传机制,触发重传机制主要有两种情况:

  1. 数据丢包(发送失败)
  2. 确认应答丢失(接受返回ACK信息失败)

如图所示:
在这里插入图片描述
至于如何确定超时时间,这方面的专家们都是经过大量的数据实验所得出来的,大家知道就行了,超时重传的时间一般来说,是略大于一次报文来回的时间的。

实际上报文往返 RTT 的值是经常变化的,因为我们的网络也是时常变化的。也就因为报文往返 RTT 的值是经常波动变化的,所以超时重传时间 RTO 的值应该是一个动态变化的值。这些都是经过大量实验所得。

每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。

超时重传的问题:等待时间很长!所以需要一个快速的重传机制,来解决超时重传的等待时间。

快速重传

如下图所示:

发送端收到了三个 Ack = 2 的确认,知道了 Seq2 还没有收到,就会在定时器过期之前,重传丢失的 Seq2。最后,接收到收到了 Seq2,此时因为 Seq3,Seq4,Seq5 都收到了,于是 Ack 回 6 。
在这里插入图片描述
所以,快速重传的工作方式是当收到三个相同的 ACK 报文时,会在定时器过期之前,重传丢失的报文段。

但是依然还是存在一些问题:快速重传机制只解决了一个问题,就是超时时间的问题,但是它依然面临着另外一个问题。就是重传的时候,是重传之前的一个,还是重传所有的问题。

比如对于上面的例子,是重传 Seq2 呢?还是重传 Seq2、Seq3、Seq4、Seq5 呢?因为发送端并不清楚这连续的三个 Ack 2 是谁传回来的。

为了解决不知道该重传哪些 TCP 报文,于是就有 SACK 方法。

SACK

sack是一种选择性的确认信息,这里的s 就是 selective ,选择性的返回确认信息。

这种方式需要在 TCP 头部字段里加一个 SACK 的东西,它可以将缓存的信息发送给发送方,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据。

如图所示:在返回的ack信息的时候携带SACK信息,告诉发送方哪些数据是被接收方所接收。

在这里插入图片描述
需要注意的是:如果要支持 SACK,必须双方都要支持。在 Linux 下,可以通过 net.ipv4.tcp_sack 参数打开这个功能(Linux 2.4 后默认打开)。

D-SACK (Duplicate SACK)

相对于sack,这种方式可以让发送方知道有哪些数据被重复接收了。

例如:

  1. ack信息丢包
    在这里插入图片描述
    两个 ACK 确认应答都丢失了,所以发送方超时后,重传第一个数据包(3000 ~ 3499),接收方发现数据是重复收到的,于是回了一个 SACK = 3000-3500,告诉发送方 3000~3500 的数据早已被接收了,因为 ACK 都到了 4000 了,已经意味着 4000 之前的所有数据都已收到,所以这个 SACK 就代表着 D-SACK。这样发送方就知道了,数据没有丢,是接收方的 ACK 确认报文丢了。

  2. 网络延迟
    在这里插入图片描述
    从上面的图可以看到,在触发重传后,接收方回了一个 SACK=1000~1500,因为 ACK 已经到了 3000,所以这个 SACK 是 D-SACK,表示收到了重复的包。这样发送方就知道快速重传触发的原因不是发出去的包丢了,也不是因为回应的 ACK 包丢了,而是因为网络延迟了。

注意:在 Linux 下可以通过 net.ipv4.tcp_dsack 参数开启/关闭这个功能(Linux 2.4 后默认打开)。

滑动窗口

TCP 是每发送一个数据,都要进行一次确认应答。当上一个数据包收到了应答了, 再发送下一个。但是这样的话,TCP 的一个通讯效率就会很低,所以就引入了滑动窗口的概念:那么有了窗口,就可以指定窗口大小,窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。

窗口的实现实际上是操作系统开辟的一个缓存空间,发送方主机在等到确认应答返回之前,必须在缓冲区中保留已发送的数据。如果按期收到确认应答,此时数据就可以从缓存区清除。

这里就有点类似 Java 里面的消息队列,发送方只负责往消息队列里面丢,消费者负责去消费,只要在窗口的范围内,各司其职,提高整体的一个并行处理的效率,如下图所示:

在这里插入图片描述

那么窗口的大小由什么决定

TCP 头里有一个字段叫 Window,也就是窗口大小。

这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来,通常窗口的大小是由接收方的决定的。

发送方的滑动窗口:

如图所示:#1区域就是已经发送并且确认的消息;#2是已经发送,但是还没收到确认信息的一部分数据;#3就是还没发送,但是已经快到达接收放的处理范围了;#4部分则需要一直等待,因为再发送就超过接收方的处理极限了
在这里插入图片描述
TCP 滑动窗口方案使用三个指针来跟踪在四个传输类别中的每一个类别中的字节。其中两个指针是绝对指针(指特定的序列号),一个是相对指针(需要做偏移)。

如下图所示:
在这里插入图片描述

  1. SND.WND:表示发送窗口的大小(大小是由接收方指定的);
  2. SND.UNA:是一个绝对指针,它指向的是已发送但未收到确认的第一个字节的序列号,也就是 #2 的第一个字节;
  3. SND.NXT:也是一个绝对指针,它指向未发送但可发送范围的第一个字节的序列号,也就是 #3 的第一个字节;
  4. 指向 #4 的第一个字节是个相对指针,它需要 SND.UNA 指针加上 SND.WND 大小的偏移量,就可以指向 #4 的第一个字节了

接收方的滑动窗口

如下图所示:
在这里插入图片描述

接收方和发送方的窗口大小相等吗?

是接近相等的,但是一般来说发送方的窗口要略小于接收方的,不然接收放都处理不过来,发送再多也没有意义。

当然,滑动窗口并不是一成不变的。比如,当接收方的应用进程读取数据的速度非常快的话,这样的话接收窗口可以很快的就空缺出来。那么新的接收窗口大小,是通过 TCP 报文中的 Windows 字段来告诉发送方。

流量控制

如果一直无脑的发数据给对方,但对方处理不过来,那么就会导致触发重发机制,从而导致网络流量的无端的浪费。为了解决这种现象发生,TCP 提供一种机制可以让发送方根据接收方的实际接收能力控制发送的数据量,这就是所谓的流量控制。

如下图所示:1. 服务端非常的繁忙,当收到客户端的数据时,应用层不能及时读取数据。

在这里插入图片描述
在最后,服务端收到 80 字节数据,但是应用程序依然没有读取任何数据,这 80 字节留在了缓冲区,于是接收窗口收缩到了 0,并在发送确认信息时,通过窗口大小给客户端。客户端收到确认和窗口通告报文后,发送窗口减少为 0。

如图所示:2. 当服务端系统资源非常紧张的时候,操作系统可能会直接减少了接收缓冲区大小,这时应用程序又无法及时读取缓存数据,那么这时候就会出现数据包丢失的现象。
在这里插入图片描述
所以,如果发生了先减少缓存,再收缩窗口,就会出现丢包的现象。

为了防止这种情况发生,TCP 规定是不允许同时减少缓存又收缩窗口的,而是采用先收缩窗口,过段时间在减少缓存,这样就可以避免了丢包情况。

窗口关闭

如果窗口大小为 0 时,就会阻止发送方给接收方传递数据,直到窗口变为非 0 为止,这就是窗口关闭。那窗口关闭会出现问题吗?

答案是会的,如图所示:如果这个通告窗口的 ACK 报文在网络中丢失了,这会导致发送方一直等待接收方的非 0 窗口通知,接收方也一直等待发送方的数据,如不不采取措施,这种相互等待的过程,会造成了死锁的现象。
在这里插入图片描述
所以如何解决?

给一个定时器,只要 TCP 连接一方收到对方的零窗口通知,就启动持续计时器。如果持续计时器超时,就会发送窗口探测报文,而对方在确认这个探测报文时,给出自己现在的接收窗口大小。

如下图所示:

在这里插入图片描述
窗口探查探测的次数一般为 3 此次,每次次大约 30-60 秒(不同的实现可能会不一样)。如果 3 次过后接收窗口还是 0 的话,有的 TCP 实现就会发 RST 报文来中断连接。

拥塞控制

读者阅读到这里肯定有一个跟我一样的疑惑,就是为什么前面有流量控制,为啥还要有拥塞控制?

其实流量控制只是控制信息接收放和发送方的一个能力,但是在计算机的网络中,有很多不确定性因素,例如网络波动等,网络带宽等,也有可能会因为其他主机之间的通信使得网络拥堵。

在网络出现拥堵时,如果继续发送大量数据包,可能会导致数据包时延、丢失等,这时 TCP 就会重传数据,但是一重传就会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这个情况就会进入恶性循环被不断地放大。

拥塞窗口 cwnd是发送方维护的一个 的状态变量,它会根据网络的拥塞程度动态变化的。其实只要发送方没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了用拥塞。

拥塞控制主要是四个算法:

  1. 慢启动
  2. 拥塞避免
  3. 拥塞发生
  4. 快速恢复

慢启动

TCP 在刚建立连接完成后,首先是有个慢启动的过程,这个慢启动的意思就是一点一点的提高发送数据包的数量,如果一上来就发大量的数据,这不是给网络添堵吗?

慢启动的算法记住一个规则就行:当发送方每收到一个 ACK,就拥塞窗口 cwnd 的大小就会加 1。

如下图所示:
在这里插入图片描述
那慢启动涨到什么时候是个头呢?
有一个叫慢启动门限 ssthresh (slow start threshold)状态变量。

  1. 当 cwnd < ssthresh 时,使用:慢启动算法
  2. 当 cwnd >= ssthresh 时,就会使用:拥塞避免算法

拥塞避免

前面说道,当拥塞窗口 cwnd 超过慢启动门限 ssthresh 就会进入拥塞避免算法。一般来说 ssthresh 的大小是 65535 字节。那么进入拥塞避免算法后,它的规则是:每当收到一个 ACK 时,cwnd 增加 1/cwnd。
在这里插入图片描述
所以,我们可以发现,拥塞避免算法就是将原本慢启动算法的指数增长变成了线性增长,还是增长阶段,但是增长速度缓慢了一些。就这么一直增长着后,网络就会慢慢进入了拥塞的状况了,于是就会出现丢包现象,这时就需要对丢失的数据包进行重传。当触发了重传机制,也就进入了拥塞发生算法。

拥塞发生算法

当网络出现拥塞,也就是会发生数据包重传,重传机制主要有两种:

  1. 超时重传
  2. 快速重传

这两种使用的拥塞发送算法是不同的

当发生了超时重传,则就会使用拥塞发生算法,这个时候,sshresh 和 cwnd 的值会发生变化:

  1. ssthresh 设为 cwnd/2(新的慢启动阈值)
  2. cwnd 重置为 1(拥塞窗口 cwnd重置为1)

如图所示:
在这里插入图片描述
发生快速重传的拥塞发生算法:
TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分,则 ssthresh 和 cwnd 变化如下:

  1. cwnd = cwnd/2 ,也就是设置为原来的一半;
  2. ssthresh = cwnd;
  3. 进入快速恢复算法

快速恢复算法:

快速重传和快速恢复算法一般同时使用,快速恢复算法是认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕,所以没有必要像 RTO 超时那么强烈。正如前面所说,进入快速恢复之前,cwnd 和 ssthresh 已被更新了,然后,进入快速恢复算法如下:

  1. 拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了,这里的ssthresh 就是上面快速恢复的新的阈值6,所以这里 6+3 = 9)
  2. 重传丢失的数据包
  3. 如果再收到重复的 ACK,那么 cwnd 增加 1(9 + 1 = 10)
  4. 如果收到新数据的 ACK 后,设置 cwnd 为 ssthresh,接着就进入了拥塞避免算法

如下图所示:
在这里插入图片描述

最后

TCP 远不止此,网络世界变化莫测,不断地学习,不断地提升,读者共勉。

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

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

相关文章

Work20230705

//main.c #include "uart4.h" extern void printf(const char *fmt, ...); void delay_ms(int ms) {int i,j;for(i 0; i < ms;i)for (j 0; j < 1800; j); }int main() {while(1){//将获取到的字符1发送到终端//hal_put_char(hal_get_char()1);hal_put_string…

chatGPT之100个例子-从体验到精通

简介 本博文演示了100个chatGPT在各行各业的使用例子,全部看完有助于培养chatGPT解决问题的思维。 在人工智能时代,智能软件并不会淘汰人类,淘汰人类的是会使用人工智能的人! 我们直接使用openAI官方chatGPT,生动演示了chatGPT的一些妙用! 请仔细看完,一定会有收获! 每…

[期末网页作业]-精仿华为官网10个网页(html+css+js)

经过漫长的期末考试季节&#xff0c;我成功地完成了一个华为官网的仿写项目&#xff0c;并且非常高兴地与大家分享。这个项目包含了10个页面&#xff0c;每一个页面都经过了精心的设计和努力的填充。 首先&#xff0c;我注重了页面的整体布局与设计。借鉴了华为官网的风格&…

apache php mysql python 环境部署与离线安装deb包

文章目录 1.背景介绍2. 主要涉及操作2.1 安装系统&#xff1a;2.2 apache mysql php安装2.3 配置2.4 python相关库安装 3. 操作记录3.1 软件安装3.2 读取文件内容后进行文件内容抽取3.3 执行以上的sh脚本3.4 所学3.5 打包发送 4. 参考文献 1.背景介绍 使用的系统为ubuntu18.04…

vscode安装+配置+使用+调试【保姆级教程】

1. VScode是什么 Visual Studio Code简称VS Code&#xff0c;是一款跨平台的、免费且开源的现代轻量级代码编辑器&#xff0c;支持几乎主流开发语言的语法高亮、智能代码补全、自定义快捷键、括号匹配和颜色区分、代码片段提示、代码对比等特性&#xff0c;也拥有对git的开箱即…

架构师进阶之路 - 微服务怎么划分

目录 微服务划分目标 业务、技术、团队导向规划服务 领域检查 依赖DAG检查 分布式事务检查 性能分布检查 稳定&#xff08;易变&#xff09;性检查 调用链检查 微服务划分目标 我们常说服务的合理划分是微服务成功的重中之重&#xff0c;一个合理的服务划分应该符合一下…

Linux性能优化实践——CPU上下文

CPU上下文切换 Linux是一个多任务操作系统&#xff0c;它支持远大于CPU数量的任务同时运行。这些任务不是真正意义上的并行运行&#xff0c;而是系统在短时间内&#xff0c;将CPU轮流分配给它们&#xff0c;造成任务同时运行的错觉。 CPU需要知道任务从哪里加载&#xff0c;从…

Linux调优–I/O 调度器

Linux 的 I/O 调度器是一个以块式 I/O 访问存储卷的进程&#xff0c;有时也叫磁盘调度器。Linux I/O 调度器的工作机制是控制块设备的请求队列&#xff1a;确定队列中哪些 I/O 的优先级更高以及何时下发 I/O 到块设备&#xff0c;以此来减少磁盘寻道时间&#xff0c;从而提高系…

QC51XX---I2c使用

QCC51XX---系统学习目录_嵌入式学习_force的博客-CSDN博客 今天我们聊聊I2C的使用。在开发过程中多多少少会加入一些外围传感器可以给用户带来更好的使用体验。例如,利用接近传感器识别戴上耳机和取下耳机,从而去自动暂停播放音乐,或接听转移通话。又例如,用触摸或敲击替代…

软件安全技术复习内容

软件安全技术 边复习边写的&#xff0c;有错误及时指正第一章 软件安全概述零日漏洞安全威胁分类CIA安全基本属性PDRR模型软件安全的主要方法和技术基本方法主要技术 第二章 软件漏洞概述概念软件漏洞成因分析软件漏洞分类基于漏洞成因的分类基于漏洞利用位置的分类基于威胁类型…

基于Stable Diffusion的2D游戏关卡生成【实战】

接下来的几篇文章将与常规主题有所不同&#xff08;这是在从事通用机器人技术的职业中吸取的教训&#xff09;。 相反&#xff0c;我决定利用我的一些新空闲时间 1 边做边学&#xff0c;并使用所有酷孩子都在谈论的一些很酷的新 ML。 推荐&#xff1a;用 NSDT设计器 快速搭建可…

第五章 运输层【计算机网络】

第五章 运输层【计算机网络】 前言推荐第五章 运输层5.1运输层协议概述5.1.1 进程之间的通信5.1.2运输层的两个主要协议5.1.3运输层的端口 5.2用户数据报协议UDP5.2.1UDP概述5.2.2UDP的首部格式 5.3传输控制协议TCP概述5.3.1TCP最主要的特点5.3.2TCP的连接 5.4可靠传输的工作原…

Node中express路由基本使用

1.路由的基本使用 //引入express const expressrequire("express") //创建路由 const appexpress() //规定路由的请求方法 app.get(/,(req,res)>{res.end("hello express") }) //启动路由&#xff0c;并且端口为9000 app.listen(9000,()>{console.l…

通俗易懂讲解CPU、GPU、FPGA的特点

1. CPU vs GPU 大家可以简单的将CPU理解为学识渊博的教授&#xff0c;什么都精通&#xff1b;而GPU则是一堆小学生&#xff0c;只会简单的算数运算。可即使教授再神通广大&#xff0c;也不能一秒钟内计算出500次加减法。因此&#xff0c;对简单重复的计算来说&#xff0c;单单一…

注册HTTPS证书

注册HTTPS证书 1. 从ACME获取脚本文件2. 运行shell脚本3. 安装socat4. 把acme.sh这个脚本添加到环境变量软连接直接添加到.bashrc 5. 注册ACME账户6. 注册证书6.1. 首先把80端口打开6.2. 申请证书 7. 部署到Flask上 1. 从ACME获取脚本文件 wget https://get.acme.shmv index.ht…

多元分类预测 | Matlab 鲸鱼算法(WOA)优化xgboost的分类预测模型,多特征输入模型,WOA-xgboost分类预测

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元分类预测 | Matlab 鲸鱼算法(WOA)优化xgboost的分类预测模型,多特征输入模型,WOA-xgboost分类预测 多特征输入单输出的二分类及多分类模型。程序内注释详细,直接替换数据就可以用。程序语言为matlab,程序可…

python接口自动化(二十三)--unittest断言——上(详解)

简介 在测试用例中&#xff0c;执行完测试用例后&#xff0c;最后一步是判断测试结果是 pass 还是 fail&#xff0c;自动化测试脚本里面一般把这种生成测试结果的方法称为断言&#xff08;assert&#xff09;。用 unittest 组件测试用例的时候&#xff0c;断言的方法还是很多的…

最新AI创作系统V5.0.2+支持GPT4+支持ai绘画+实时语音识别输入+文章资讯发布功能+用户会员套餐

最新AI创作系统V5.0.2支持GPT4支持ai绘画实时语音识别输入文章资讯发布功能用户会员套餐&#xff01; AI创作系统一、源码系统介绍二、AI创作系统程序下载三、安装教程四、主要功能展示五、更新日志 AI创作系统 1、提问&#xff1a;程序已经支持GPT3.5、GPT4.0接口 2、支持三种…

python爬虫_django+vue+echarts可视化查询所有CSDN用户质量分

文章目录 ⭐前言⭐ 效果⭐django简介⭐vue3简介⭐vue引入echarts ⭐前后分离实现&#x1f496; django代码层&#x1f496; vue3代码层结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享关于前后分离djangovueecharts可视化查询CSDN用户质量分。 该系列文章&#…

Elasticsearch集群

单点的问题 单台机器存储容量有限&#xff0c;无法实现高存储。 单服务器容易出现单点故障&#xff0c;无法实现高可用。 单服务的并发处理能⼒有限&#xff0c;无法实现高并发。 集群的结构 数据分片:把数据拆分成多份&#xff0c;每一份存储到不同机器节点&a…