TCP的可靠性之道:确认重传和流量控制

TCP 全称为 Transmission Control Protocol(传输控制协议),是一种面向连接的、可靠的、基于字节流的传输层通信协议,其中可靠性是相对于其他传输协议的优势点。TCP 为了确保数据传输的可靠性主要做了以下几点:

  • 发送确认机制
  • 丢包重传机制
  • 滑动窗口
  • 拥塞控制

TCP 的传输基于字节流,记录起始序列号、是否发送、是否接收。本文从实战出发,使用 Wireshark 抓包工具来分析具体的请求。

确认和重传

  • TCP 报文头中有两个字段:
    • Sequence number 序列号:表示要发送数据的起始号
    • Acknowledgment number 确认号:表示消息已经接收,返回下次要发送的起始号

发送确认

TCP 每次发送数据,都有一个确认应答 ACK,表示已经收到了数据包。确认号表示下一个传送的起始号。

发送一个 http 请求,使用 Wireshake 抓取数据包,打开 Statistics -> Flow Graph,在弹出的页面上将 Flow type 修改成 TCP Flows,就能看到 TCP 的数据包请求:

上图中标记了三个地方,中间的的标记的发送确认,就表示数据发送和确认应答,len 表示字节长度。发送 1 ~ 218 的字节,确认应答返回了确认号 219。第二个发送确认也是类似原理,所不同的是,这个发送确认时接收端的发送确认。

重传机制

发送端的数据包,一般都发送到接收端。但是在网络不好,或者信号比较差的情况,可能就无法正常发送到数据。

先介绍两个概念,RTTRTO

RTT Round-Trip Time 表示往返时间,表示网络一段到另一端所需要的时间,也就是数据包的往返时间,以 TCP 握手为例:

RTT 表示数据包从发送到收到确认应答的时间。

RTO Retransmission Timeout 表示超时重传时间。超过这个时间没有确认应答,就会重传报文段,这个时间根据 RTT 来设置的。

重传机制是 TCP 基本的错误恢复功能,常见的重传机制有两种:

  • 超时重传
  • 快速重传

1、超时重传

超时重传,字面意思是,超时规定的时间没有收到确认消息,就会再次发送一个消息请求。TCP 发送方发送报文时,会设置一个定时器,如果在时间范围内没有收到接收方发来的 ACK 确认报文,发送方就会重传已经发送的报文段。

TCP 有两种超时重传的情况:

  • 报文在发送途中丢失
  • 确认包在途中丢失

上面的 RTO 表示超时重传时间,RTO 的设定不能过大的或者过小:

  • 如果过大,请求等待的时间过长,请求的效率低。
  • 如果过小,正常返回的确认还未来得及返回,就重传。加大网络符合。

设置一个适当的 RTO 才会让重传机制更加高效。超时时间 RTT 应该略大于往返时间 RTT

如果超时重传的报文段又超时了该怎么办呢?,答案就是重传的超时时间加倍,也就是再次超时重传的超时时间会增加到之前的两倍。

如果超时重传的报文段又丢包呢?此时发送方会以 RTO 时间的 2、4、8倍的倍数尝试多次重传。

超时重传如果消息多次没有收到确认报文,超时的周期也比较长,有没有更加高效的方法减少超时重传的时间呢?就引出下面的要讲的快速重传。

快速重传

快速重传不会等待超时时间到了再重传,发送方收到 3 次重复确认报文端,就不会等超时时间重试,而是直接重传报文。

连续发送的报文段,中间只要有一个丢失,后续返回的确认号都是相同,后面的报文段无论有没有返回,都会重传一遍,这种设置还是比较合理的。在一段时间内,如果网络状况不好,导致丢包情况,后续的报文段一般也会丢包。

但是重传丢包后面所有的包,也会造成网络传输的浪费。对于上面的例子,如果只想传输 seq2,其他有返回的确认包就不用重传。

TCP 有一种重传机制: SACK Selective Acknowledgment 选择性重传。

这种方式需要 TCP 报文段选项加一个 SACK 字段,使用查看 Wireshake SYN 包中 SACK Permitted:

发送包有返回确认应答,就会发送给发送方告知对应的数据被接收了,发送方就能记录哪些数据被接收了,哪些数据没有被接收。后面只会重传没有被接收的数据包,这就是选择性重传。

滑动窗口

TCP 发送比较大的数据包,TCP 会一次性发送大的数据包给接收方?答案是不会的,需要考虑网络带宽,TCP 会将大的数据包拆分成多个大小适中的数据包,发送一个 http 请求,添加较大的参数,使用 Wireshake 抓取数据包:

数据包被拆分成五个小的数据包。

数据包被拆分成多个小的数据包之后,数据包发送都有返回一个确认序列号,每次发送一个新的包,都等待上一个包的 ACK 回来之后才能发送,这样一来一回的效率是很低的:

TCP 为了解决这个问题,引入窗口的概念,在窗口范围内的数据包,无需等待上一次 ACK 确认,可以直接发送数据包:

滑动窗口是 TCP 协议中的一种流量控制机制,用来控制发送方和接收方数据传输的速率,避免数据过多造成数据无法及时处理。

窗口的大小也就是 TCP 报文段的 windos 字段,表示的就是接收方目前能接收的缓冲区的剩余大小,发送端根据这个字段处理发送的数据。

发送端的窗口

发送窗口根据三个标准来划分:是否发送、是否收到 ACK、是否在接收方处理范围内,分成了四个部分:

四个部分组成:

  • 第一部分是已经发送并收到 ACK 确认的数据,这部分数据已经发送成功了,无需在缓存中保留了。
  • 第二部分数据是已经发生但是未收到 ACK 确认的数据。
  • 第三部分数据是未发送,但是在接收方处理范围之内的数据。第二、第三部分共同组成发送的窗口。
  • 第四部分是需要发送,但是未在接收方范围之内的数据。这部分数据在没有接收 ACK 确认之前,是不会发送数据的。

如果发送方一直没有收到 ACK,数据不断的发送,很快可用窗口也被耗尽,这时发送方也不会继续发送数据了,这时发送端可用窗口为零的情况我们成为“零窗口”。

随着 ACK 的确认,窗口也会依次向右滑动,比如发送端的窗口中,比如 40 ~ 43 字节都收到了 ACK 确认,那么整个可用的窗口就会顺次往右移动。此时 53 ~ 57的数据也都能发送了。

接收端的窗口

接收端的滑动窗口相对发送的窗口要简单的多,主要分为三个部分:

  • 已经接收并确认的数据
  • 可以接收但是未接收的数据
  • 在接收范围之外(不够缓存的数据),也就是不可以接收的数据。

但数据接收后,窗口也向右边滑动,给发生端的数据提供数据缓存。如果读取缓存的数据速度有变化时,接收端可能也会改变接收窗口的大小,以此来控制发送端的发送速度。这就是滑动窗口进行流量控制的一种机制。

拥塞控制

网络中由于有大量的包传输,在固定带宽下处理不过来数据包的传输,可能会导致数据包阻塞,网络传输的速度下降,甚至会下降到 0 的情况。这就有点类似排队买东西,如果正常排队,速度虽然不快但处理速度比较稳定。但是如果一下涌来很多人口,就会处理不过来,导致堵死情况

而 TCP 被设置成一个无私的协议,当遇到网络拥塞时,TCP 会减少自己发送数据包,这样网络拥塞会得到很大的缓解。

为了实现拥塞控制,首先在发送端定义一个拥塞窗口 CWND (congestion window),限制发送端发送数据最多没有收到 ACK 确认包的大小,超过拥塞窗口范围后,就不会继续发送数据了

拥塞窗口会随着网络情况的变化动态的调用自身的大小,大体的变化规则是:如果没有出现拥塞,就扩大窗口大小,否则就缩小窗口的大小。

拥塞控制算法主要包含四个部分:

  • 慢启动
  • 拥塞避免
  • 拥塞发生
  • 快速恢复

慢启动

当一个新的TCP连接开始时,无法确定是否用拥塞发生,一开始不会发送大量的包,而是从最小的发送窗口开始,后续会采用倍增的方式增加窗口的大小,窗口大小从 1 开始,后续慢慢增大到 2、4、8 等。

指数增加速度会越来越快,窗口扩大的一定的程度,就会减慢增加的速度,改成线性增加,这时候就进入拥塞避免阶段。

拥塞避免

慢启动和拥塞避免的临界点叫做慢启动门限 ssthresh (slow start threshold。

  • cwnd < ssthresh 时,使用慢启动算法。
  • cwnd >= ssthresh 时,就会使用「拥塞避免算法」。

ssthresh 大小一般是 65535 字节。拥塞避免的规则是:每当收到一个 ACK 时,cwnd 增加 1/cwnd。就变成线性增长了。

拥塞发生

拥塞避免将原来的指数增长改成了线性增长,虽然增长速度减慢,但 CWND 窗口还是在增长阶段。随着窗口进一步缓慢增加,网络还是会遇到阻塞的状态,会出现丢包的情况。就需要对丢包进行重传。

重传机制有两种:

  • 超时重传
  • 快速重传

当发生超时重传时,sshresh 和 cwnd 的值会发生如下变化:

  • sshresh 变成 cwnd 的一半
  • cwnd 重置为 1

cwnd 重置为1,表示直接进入慢启动状态。

上面的超时重传速度变化太快,而快速重传是一个相对温和的方案。如果我们连续 3 次收到同样序号的 ACK,包还能回传,说明这个时候可能只是碰到了部分丢包,网络阻塞还没有很严重,无需重置 cwnd。

此时 ssthresh 和 cwnd 变化如下:

  • cwnd = cwnd/2 ,也就是设置为原来的一半;
  • ssthresh = cwnd

并进入到快速恢复阶段。

快速恢复

快速恢复主要是将 cwnd 恢复到正常大小,上面说的 cwnd 设置成原来的一半,ssthresh 设置成 cwnd 的大小。

快速恢复算法如下:

  • 重传丢失的数据包。
  • 如果接收到重复 ACK 确认,cwnd 增加 1。
  • 如果接收到新数据的 ACK 确认,就将 ssthresh 恢复到慢启动时期的值,因为返回新数据的 ACK 确认,表示网络阻塞已经结束,可以恢复到之前的状态,cwnd 也可以指数或者线性增加。

总结

TCP 提供基于字节流、可靠的数据传输,为了确保数据的可靠性,做了很多工作:

  • 报文段序号和确认号
    • 每个报文都有序号和确认号,序号表示报文段第一个字节号,确认号表示下一个接收字节的序号。
  • 发送确认和重传机制
    • 每个报文段发送后,都会确认应答 ACK,表示已经报文段已经成功发送。
    • 当网络异常数据包无法达到时,就会触发重传机制。重传主要有两种方式:超时重传和快速重传。
    • 超时重传:设置一个定时器,超过时间未收到确认应答,就会重新传数数据包。这个重传方式周期比较长。
    • 快速重传:快速重传不会等待超时时间到了再重传,是以数据为基点,发送多次报文段,当接受到重复的确认应答号 ACK 时,直接重传所有的报文段。可以使用 SACK 记录哪些报文段已经成功接收了,只重传没有被成功接收的报文段。
  • 滑动窗口
    • 报文段拆分,TCP 将要发送的数据拆分适当大小的数据包。
    • 引入窗口的概念,这个窗口大小是由接收方来决定,表示接收方可以接收的缓存大小。在窗口范围之内, TCP 可以连续发送多个数据包给接收方,当数据包发送并且有确认应答,整个窗口会往后移动,继续发送新的数据。
    • 随着数据传输的速度和网络情况,接受方可能会动态修改窗口的大小,以此来控制数据传输的速度。
    • 滑动窗口能流量进行控制,控制数据发送的速度和频率,避免出现拥塞情况。
  • 拥塞控制,在网络传输中可能会出现大量的数据请求,而固定的网络宽带可能处理不过来这么多数据传输,容易形成阻塞的情况。TCP 遇到网络拥塞时,会自动减少自己发送包的数量,这样网络拥塞情况就会缓解。TCP 发送端定义拥塞窗口 CWND,表示没有接收到 ACK 确认数据的最大发送量。拥塞控制算法主要包含四个部分:
    • 慢启动:开始一个新的连接时,从较小的发送窗口开始,然后指数增长增加 CWND 窗口大小,知道达到慢启动门限。
    • 拥塞避免:窗口达到慢启动门限临界点时候,慢启动阶段结束,这个阶段,窗口大小线性增加,增长速度比较慢,避免发生网络拥塞。
    • 拥塞发生:窗口进一步缓慢增加,网络还是会遇到阻塞的状态,会出现丢包的情况。就需要对丢包进行重传。此时有两种重传机制:超时重传和快速重传。超时重传,是窗口大小重置为 1,数据传输又恢复成慢启动时的速度。这种传输速度急剧下降,不利于系统稳定,由于窗口大小限制,网络传输次数更多,拥塞的情况也会更大。而快速重传是相对温和的方案,此时认为网络只是暂时有阻塞情况,将窗口大小 CWND 改成原来的一半,并进入快速恢复阶段。
    • 快速恢复:重传丢失的数据包,如果接收到重复 ACK 确认,cwnd 增加 1。如果接收到新数据的 ACK 确认,就将 ssthresh 恢复到慢启动时期的值,因为返回新数据的 ACK 确认,表示网络阻塞已经结束,cwnd 也可以指数或者线性增加。

参考

  • TCP 重传、滑动窗口、流量控制、拥塞控制

  • 滑动窗口:TCP是如何进行流量控制和拥塞控制的

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

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

相关文章

电脑文件删除了可以找回吗?分享一种简单恢复删除电脑文件办法!

电脑文件删除了可以找回吗&#xff1f;可以。在原理上讲电脑删除的文件是有希望恢复的&#xff0c;因为操作系统在删除文件的时候并会不会立刻将文件彻底删除。当文件被删除的时候&#xff0c;其文件记录被删除&#xff0c;并且被文件占用的磁盘空间被标记为空闲。 这样对于用户…

1.1 VMware Workstation与Kali的安装和配置1

资源见专栏第一篇文章https://blog.csdn.net/algorithmyyds/article/details/132457258 安装VMware 不多加赘述&#xff0c;直接按顺序安装即可。 有以下需注意的地方&#xff1a; 1.建议选择增强型服务&#xff1b; 2.不要加入体验改进计划。是否开启提示更新看你的想法&…

Nvidia Jetson 编解码开发(7)Jetpack 4.x版本Multimedia API 硬件编码开发--输出端对接ROS publish

1.前言 Nvidia Jetson 编解码开发(6)Jetpack 4.x版本Multimedia API 硬件编码开发--输入端对接Camera V4L2采集_free-xx的博客-CSDN博客 基于上篇基于开发 需求: (1)2路Camera采集 + H265编码 (2)2路编码完的H265数据通过ROS 发布出去,上位机播放 2. 开发记录 2…

【linux】2 make/Makefile和gitee

文章目录 一、Linux项目自动化构建工具-make/Makefile1.1 背景1.2 实例代码1.3 原理1.4 项目清理 二、linux下第一个小程序-进度条2.1 行缓冲区2.2 进度条 三、git以及gitee总结 ヾ(๑╹◡╹)&#xff89;" 人总要为过去的懒惰而付出代价ヾ(๑╹◡╹)&#xff89;" 一…

盛最多水的容器——力扣11

int maxArea(vector<int>& height) {int l=0, r=height.size()

半导体低压热氧工艺中的真空度精密控制解决方案

摘要&#xff1a;在目前的各种半导体材料热氧化工艺中&#xff0c;往往需要对正负压力进行准确控制并对温度变化做出快速的响应&#xff0c;为此本文提出了热氧化工艺的正负压力控制解决方案。解决方案的核心是基于动态平衡法分别对进气和排气流量进行快速调节&#xff0c;具体…

SpringBoot 微人事 职称管理模块(十三)

职称管理前端页面设计 在职称管理页面添加输入框 export default {name: "JobLevelMarna",data(){return{Jl:{name:""}}}}效果图 添加一个下拉框 v-model的值为当前被选中的el-option的 value 属性值 <el-select v-model"Jl.titlelevel" …

Spring cache整合Redis使用介绍

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

【网络教程】如何创建/添加钉钉机器人以及如何获取机器人的Token/Secret

文章目录 创建钉钉机器人添加钉钉机器人获取机器人的Token/Secret相关网站创建钉钉机器人 这里以PC端的操作为例,按照如下操作进行 访问 钉钉开放平台选择机器人选项卡,点击右上角的创建应用,这里会有一个弹窗,我这里选择的是继续使用旧版,如图按照要求填写相关信息创建自…

第六次作业 运维高级 docker容器

1.安装docker服务&#xff0c;配置镜像加速器 卸载旧版本 yum remove docker docker-common docker-selinux docker-engine使用yum源安装 &#xff08;1&#xff09;安装Docker所需要的一些工具包 yum install -y yum-utils&#xff08;2&#xff09; 建立Docker仓库 (映射…

Java——它要求用户输入一个整数(实际上是一个字符串),然后计算该整数的平方值,并将结果输出。

这是一个Java程序&#xff0c;它要求用户输入一个整数&#xff08;实际上是一个字符串&#xff09;&#xff0c;然后计算该整数的平方值&#xff0c;并将结果输出。程序的基本流程如下&#xff1a; 首先&#xff0c;声明并初始化变量data和result&#xff0c;它们的初始值都为…

扁线电机定子转子工艺及自动化装备

售&#xff1a;扁线电机 电驱对标样件 需要请联&#xff1a;shbinzer &#xff08;拆车邦&#xff09; 新能源车电机路线大趋势&#xff0c;自动化装配产线需求迫切永磁同步电机是新能源车驱动电机的主要技术路线。目前新能源车上最广泛应用的类型为永磁同步电机&#xff0c…

W5500-EVB-PICO进行UDP组播数据回环测试(九)

前言 上一章我们用我们的开发板作为UDP客户端连接服务器进行数据回环测试&#xff0c;那么本章我们进行UDP组播数据回环测试。 什么是UDP组播&#xff1f; 组播是主机间一对多的通讯模式&#xff0c; 组播是一种允许一个或多个组播源发送同一报文到多个接收者的技术。组播源将…

如何搭建智能问答FAQ的底层数据基础呢?

搭建智能问答FAQ的底层数据基础是构建一个高效和准确的问答系统的关键。在这篇文章中&#xff0c;我们将探讨如何搭建智能问答FAQ的底层数据基础&#xff0c;并介绍需要注意的几个方面。 一、了解智能问答FAQ的概念和优势 智能问答FAQ是一种基于人工智能技术的问答系统&#…

Android进阶之路 - EditText输入字体自适应

遇到这么一个需求&#xff1a;“控件宽度有限&#xff0c;随着输入内容&#xff0c;动态修改字体大小”&#xff0c;如果是你&#xff0c;只如何来实现&#xff1f;又有几种方式&#xff1f; 嗯&#xff0c;就是这么一个简单的需求&#xff0c;让我记录了俩篇blog Android进阶…

ChatGPT提示与技巧分享:如何作出更好的提示2023年8月

​对ChatGPT的一些酷炫技巧感兴趣吗?这里提供了一些可以帮助你充分利用ChatGPT&#xff0c;成为AI工具专家的技巧。 毫无疑问&#xff0c;ChatGPT是目前最广泛使用的人工智能工具之一。它不仅毫不留情地取代了一些特定领域常用的软件小工具&#xff08;如智能对联、经典语录生…

ESP32应用教程(1)— VL53L3CX距离传感器

文章目录 前言 1 产品概述 1.1 技术规格 1.2 系统框图 1.3 设备引脚分布 2 工作流程 2.1 系统功能描述 2.2 状态机描述 2.3 测距模式说明 3 控制接口 3.1 设备地址 3.2 IC写1个字节数据 3.3 IC读1个字节数据 3.4 IC写多个字节数据 3.5 IC读多个字节数据 3.6 IC…

Nacos配置管理、Feign远程调用、Gateway服务网关

1.Nacos配置管理 1.1.将配置交给Nacos管理的步骤 1.在Nacos中添加配置 Data Id服务名称-环境名称.yaml eg&#xff1a;userservice-dev.yaml 2.引入nacos-config依赖 在user-service服务中&#xff0c;引入nacos-config的客户端依赖 <!--nacos配置管理依赖--> <dep…

Flink、Yarn架构,以Flink on Yarn部署原理详解

Flink、Yarn架构&#xff0c;以Flink on Yarn部署原理详解 Flink 架构概览 Apache Flink是一个开源的分布式流处理框架&#xff0c;它可以处理实时数据流和批处理数据。Flink的架构原理是其实现的基础&#xff0c;架构原理可以分为以下四个部分&#xff1a;JobManager、TaskM…

Linux:LAMP架构与论坛搭建

目录 一、动态资源与语言 二、LAMP 架构的组成 三、CGI和astcgi 3.1CGI​​​​​​ 3.2fastcgi 3.3CGI和fastcgi比较 3.4 PHP 配置 3.5 Opcode语言 四、编译安装Apache http 服务 五、安装论坛 一、动态资源与语言 WEB 资源类型&#xff1a; 静态资源&#xff1a;原…