TCP重传机制、滑动窗口、拥塞控制
一、总述
TCP,Transmission Control Protocol,是一个面向连接、基于流式传输的可靠传输协议,考虑到的内容很多,比如数据包的丢失、损坏、分片和乱序等,TCP协议通过多种不同的机制来实现可靠传输。今天,重点分析重传机制、滑动窗口,以及拥塞控制。
二、重传机制
在三握四挥的过程中,服务器和客户端之间就通过带有不同标志位的TCP报文来通知或判断对端或本地是否成功建立、断开连接。
接收主机在接收到数据之后往往都会返回一个应答消息,网络错综复杂,面对随时可能发生的数据丢失问题,TCP使用重传机制解决。常见的重传机制有以下四种:
- 超时重传
- 快速重传
- SACK
- D_SACK
(一) 超时重传
超时重传,顾名思义,在发送数据时,会设定一个定时器,当超过指定的时间过后,没有收到对端的ACK确认应答报文,就会重写发送该数据。而这又可以分为两种情况:
- 数据包丢失
- ACK确认应答丢失
在了解如何设置超时时间之前,先来看看什么是RTT(Round-Trip Time)往返时延。

RTT,往返时延,数据从一端到另一端。其中,往返这个词是表明了什么范围是所需的时间。
知道了RTT,在来看点相关的:RTO,Retransmission Timeout,直译“超时重传时间”。这个时间的设置毫无疑问关系到我们重传机制的效率高低,看以下两种情况:
- RTO>>RTT,重发慢,没有效率;
- RTO<<RTT,包可能还没到就开始重发,重发出去的包数量多了,网络无疑会拥塞,超时的包越来越多,恶性循环。
那么结论显而易见——RTO的值,应该略大于RTT。
很容易想到的是,报文往返的RTT值会是经常变化的,所以RTO也应该是一个动态变化的值。(在Linux中,通常会采样RTT的值然后加权算平均,不详细谈了)
而在超时时,TCP的策略是超时间隔加倍。
(二) 快速重传
Fast Retransmit,快速重传,不以时间为驱动,而以数据驱动重传。

在上图中,Seq2一直没有成功被接收方收到,当发送端收到三个Ack=2的确认,就会在定时器过期之前,重传丢失的Seq2。
不过,发送方并不知道Ack=2是谁传回来的,那么是重传Seq2还是把之前的所有包都重传呢?根据TCP实现的不同,上述两种情况都是可能的。
(三) SACK
SACK是指Selective Acknowledgment,选择性确认,这种方式通过在TCP头部"选项"字段添加一个SACK,把缓存的地图发送给发送方,这样发送方就知道哪些数据需要重传了。

如果要支持SACK,双方都要支持,在Linux下,通过net.ipv4.tcp_sack这个参数打开(Linux2.4后默认打开)。
(四) Duplicate SACK
D_SACK,主要使用SACK来通知发送方有哪些数据被重复接收了,下面通过两个例子来说明,这个Duplicate到底有什么妙用。
- ACK丢包

发送端通过ACK和SACK就可以明确,是发出去的包丢了还是接收方返回的ACK确认报文丢了。
- 网络延时
在判定网络延迟时,Duplicate的含义才更加明显地体现了出来,即复制的、完全一样的。

如上图中提及,在经历了网络延迟和三次相同ACK触发快速重传后,网络延迟的包终于送达,此时返回ACK=3000,SACK=1000~1500(注意之前的SACK范围总是大于ACK),就知道了这个SACK是D_SACK,是重复的包。
三、滑动窗口(流量控制)
(一) 滑动窗口
滑动窗口,Sliding Window,是一种流量控制机制,同时也是一种保持通信效率的技术。已知的是,每当有一个数据包发出,发送端总盼望得到一个ACK确认;那么要是在得到ACK之前不做任何动作,效率的高低明显可见。
为此,TCP引入了窗口的概念,通过指定窗口大小(数据最大值),来进行无需等待确认应答的通信。
在实际实现时,是由操作系统开辟一个缓存空间。在发送方得到确认应答前,已发送的数据都会保存在缓冲区,如果按期收到确认应答,此时数据就可以从缓冲区清除。
如此一来,有了累计确认(或累计应答)模式:

- 那么引申出一个问题——窗口的大小由哪一方决定?
TCP报头中有一个16位的字段:窗口尺寸Window,这个字段是由接收方通知发送方自己还有多少缓冲区可以用来接收数据。以免接收方无法正常接收到数据。
- 发送方,滑动窗口分为4个部分

它的工作方式很容易想到:ACK确认一部分,可用窗口就扩大一部分;当发送窗口满了,在接收ACK之前就不再发送数据。
- 接收方,滑动窗口分为3个部分

值得注意的是,两个窗口的大小是约等于的关系,而不是一模一样。因为滑动窗口不是一成不变的。如果接收方的读取速度有了很大提升,会通过TCP报文通知发送方新的窗口大小。
(二) 窗口关闭问题
TCP中,通过接收方指定窗口尺寸来进行流量控制。在通信中,当接收方窗口被填满,会向发送方说明窗口尺寸位0;等处理好数据后,才会又通告一个窗口非0的ACK报文。不过,要是这个非0报文丢失,就会陷入死锁的状态(双方同时等待)。
- 窗口探测报文
为了解决这个问题,TCP为每个连接设置了一个持续计时器,只要收到0窗口通告,就启动计时器。当计时器超时,就会发送窗口探测报文,这个报文的用意显而易见。(窗口探测的次数一般是3次)。
(三) 糊涂窗口问题
糊涂窗口是指接收方在处理数据时的速度过慢,导致窗口的尺寸不断变小的现象。实际上就是两个动作让这个现象出现:
- 接收方通告小窗口
- 发送方发送小数据
想要避免这种现象,解决上述两个问题就好了。
- 在接收方,当窗口小于min(MSS, 缓存空间/2),就会告知对方0窗口,到后面合适的时机再通知非0窗口。
- 在发送方,使用Nagle算法进行延时处理,要等到发送窗口大小>=MSS,或者接收到ACK确认报文,才会停止囤积数据。这个算法是默认打开的,在使用telnet和ssh等交互性比较强的程序时,通过TCP_NODELAY来关闭。
四、拥塞控制
(一) 什么是拥塞
上文的流量控制是避免发送方的数据填满接收方的缓存,而拥塞控制,则是为了避免在整个网络环境处于拥堵时,还继续发送大量数据包的手段(可能导致数据包时延、丢失等,重传也会加重拥塞)。
那么很明显,拥塞控制是在发送端实现的。为了调节发送数据的量,定义了“拥塞窗口”的概念。
(二) 什么是拥塞窗口
拥塞窗口,是一个由发送方维护的状态变量,根据网络的拥塞程度动态变化。前面的发送窗口和接收窗口在有了拥塞窗口的加入以后,是这样的关系:
- 发送=min(拥塞,接收)
拥塞窗口的动态变化也很简答:有拥塞,就变小;没拥塞,就变大。
(三) 如何判断拥塞
只要发送方没在规定的时间内接收到ACK确认报文(发生超时重传),就会认为网络出现了拥塞。
(四) 拥塞控制算法——慢启动
TCP在刚建立完连接后,会经历慢启动,逐步提高发送数据包的数量。规则是:
- 发送方每收一个ACK,拥塞窗口cwnd的大小就增加1。
所以,这个增长是指数性的。
那什么时候是个头呢?——当达到慢启动门限(slow start threshold)后,就会使用拥塞避免算法。
(五) 拥塞避免算法
慢启动门限ssthresh一般的大小为65535字节,在进入拥塞避免算法后,窗口增长的规则是:
- 每当收到一个ACK,cwnd增加1/cwnd。
如此一来,线性增长。
在此后一直增长,网络就会进入拥塞的状态,出现丢包和丢包重传,触发了重传,也就进入了拥塞发生算法。
(六) 拥塞发生
在上文提到过,重传的机制也有两种:1. 超时重传,2. 快速重传。接下来进行分述:
- 超时重传的拥塞发生算法
ssthresh设置为cwnd/2,cwnd重置为1,然后重新开始慢启动。不过这种方式会突然减少数据流,可能网络卡顿(就像是急刹车)。
- 快速重传的拥塞发生算法
在快速重传时,接收方发送三次前一个包的ACK通知发送端重传(大部分没丢,只丢了小部分)。
cwnd=cwnd/2,ssthresh=cwnd,然后进入快速恢复算法。
(七) 快速恢复
快速重传一般和快速恢复算法同时使用,这种情况会判断网络情况并不是特别严峻,反映也不会像RTO那样强烈。
快速恢复算法:
- cwnd=ssthresh+3
- 重传丢失的数据包
- 如果再收到重复的ACK,cwnd+1
- 如果收到新ACK(说明D_SACK时的数据全部收到,恢复过程结束),cwnd=ssthresh,恢复到之前二点拥塞避免状态。
本文作为笔记,图片来源:
30 张图解: 面试必问的 TCP 重传、滑动窗口、流量控制、拥塞控制_面试回答 tcp流量控制-CSDN博客
https://blog.csdn.net/qq_34827674/article/details/105606205
相关文章:
TCP重传机制、滑动窗口、拥塞控制
一、总述 TCP,Transmission Control Protocol,是一个面向连接、基于流式传输的可靠传输协议,考虑到的内容很多,比如数据包的丢失、损坏、分片和乱序等,TCP协议通过多种不同的机制来实现可靠传输。今天,重点…...
electron+vue3全家桶+vite项目搭建【29】封装窗口工具类【3】控制窗口定向移动
文章目录 引入实现效果思路声明通用的定位对象主进程模块渲染进程测试效果 引入 demo项目地址 窗口工具类系列文章: 封装窗口工具类【1】雏形 封装窗口工具类【2】窗口组,维护窗口关系 封装窗口工具类【3】控制窗口定向移动 很多时候,我们想…...
深入了解304缓存原理:提升网站性能与加载速度
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
python-批量操作excel
批量新增excel文件 import osimport xlwings as xwapp xw.App(visibleTrue,add_bookFalse)#visible设置为ture的时候会自动打开创建的excel文件,设为为false的时候不会看到excel文件打开了,实际进程占用了....dept_list [人事部,财务部,研发部,行政部…...
#QT(串口助手-界面)
1.IDE:QTCreator 2.实验:编写串口助手 3.记录 接收框:Plain Text Edit 属性选择:Combo Box 发送框:Line Edit 广告:Group Box (1)仿照现有串口助手设计UI界面 (2)此时串口助手大…...
C语言进阶——位段
在C语言中,位段(Bit Fields)是一种用来对结构体中的成员进行位级别的控制的特性。通过位段,我们可以灵活地控制结构体中各个成员的位数,从而节省内存空间并提高程序的效率。本篇博客将详细讲解C语言中位段的相关知识&a…...
软件设计师软考题目解析23 --每日五题
想说的话:要准备软考了。0.0,其实我是不想考的,但是吧,由于本人已经学完所有知识了,只是被学校的课程给锁在那里了,不然早找工作去了。寻思着反正也无聊,就考个证玩玩。 本人github地址…...
总结:前后端集合、数组类型数据交互底层原理,SpringBoot框架解析
总结:前后端集合、数组类型数据交互底层原理,SpringBoot框架解析 一前后端信息交互本质:1.两台电脑可以通过收发电磁波、控制网线电路开关等基础物理设施,就可以进行物理层面的电信号交互,电信号又可以通过各种传感设备…...
2024蓝桥杯每日一题(前缀和)
一、第一题:壁画 解题思路:前缀和贪心枚举 仔细思考可以发现B值最大的情况是一段连续的长度为n/2上取整的序列的累加和 【Python程序代码】 import math T int(input()) for _ in range(1,1T):n int(input())s input()l math.ceil(len(s)/…...
2007-2022年上市公司迪博内部控制评价缺陷数量数据
2007-2022年上市公司迪博内部控制评价缺陷数量数据 1、时间:2007-2022年 2、范围:上市公司 3、指标:证券代码、证券简称、辖区、证监会行业、申万行业、是否存在财报内控重大缺陷、财报内控重大缺陷数量、是否存在财报内控重要缺陷、财报内…...
JAVA虚拟机实战篇之内存调优[4](内存溢出问题案例)
文章目录 版权声明修复问题内存溢出问题分类 分页查询文章接口的内存溢出问题背景解决思路问题根源解决思路 Mybatis导致的内存溢出问题背景问题根源解决思路 导出大文件内存溢出问题背景问题根源解决思路 ThreadLocal占用大量内存问题背景问题根源解决思路 文章内容审核接口的…...
qt自定义时间选择控件窗口
效果如图: 布局如图: 参考代码: //DateTimeSelectWidget #ifndef DATETIMESELECTWIDGET_H #define DATETIMESELECTWIDGET_H#include <QWidget> #include <QDateTime>namespace Ui { class DateTimeSelectWidget; }class DateTim…...
如何不解压直接读取gzip文件里面的文件
要在服务器上不解压缩的情况下读取gzip文件中的文件内容,您可以使用类似于zlib模块的库,这些库允许您在内存中对gzip数据进行操作而无需解压缩到磁盘上的文件。 在Python中,您可以使用gzip模块来实现这一目的。以下是一个示例代码࿰…...
python 截取字符串string.split
目录 作用语法只要第一个值获得第3个值遍历 作用 根据某个符号对数据进行截取 从而获得自己想要的内容 语法 使用’string.split’ 方法 对字符串’123/abc/BPYC’ 以 ‘/’ 进行截取 string "123/abc/BPYC" substring string.split("/") print(subs…...
SpringBoot+Vue实现el-table表头筛选排序(附源码)
👨💻作者简介:在笑大学牲 🎟️个人主页:无所谓^_^ ps:点赞是免费的,却可以让写博客的作者开心好几天😎 前言 后台系统对table组件的需求是最常见的,不过element-ui的el…...
Linux学习之线程
目录 线程概念 1.什么是线程? 2.线程的优缺点 3.线程异常 4.线程用途 线程操作 1.如何给线程传参 2.线程终止 3.获取返回值 4.分离状态 5.退出线程 线程的用户级地址空间: 线程的局部存储 线程的同步与互斥 互斥量mutex 数据不一致的主要过…...
【JavaEE初阶】 JVM类加载简介
文章目录 🍃前言🌲类加载过程🚩加载🚩验证🚩准备🚩解析🚩初始化 🎄双亲委派模型🚩什么是双亲委派模型?🚩双亲委派模型的优点 ⭕总结 🍃…...
.NET Core依赖注入(IoC)不使用构造函数实现注入
在.NET Core中,依赖注入(IoC)通常是通过构造函数注入来实现的,这是推荐的方式,因为它使得依赖关系更加明确和可测试。但是,如果你不想或不能使用构造函数注入,你可以考虑使用方法注入࿰…...
WinSCP下载安装并结合内网穿透实现固定公网TCP地址访问本地服务器
文章目录 1. 简介2. 软件下载安装:3. SSH链接服务器4. WinSCP使用公网TCP地址链接本地服务器5. WinSCP使用固定公网TCP地址访问服务器 1. 简介 Winscp是一个支持SSH(Secure SHell)的可视化SCP(Secure Copy)文件传输软件,它的主要功能是在本地与远程计…...
内联函数|auto关键字|范围for的语法|指针空值
文章目录 一、内联函数1.1概念1.2特性 二、auto关键字2.2类型别名思考2.3auto简介2.4auto使用细则2.4 auto不能推导的场景 三、基于范围的for循环(C11)3.1 范围for的语法 四、指针空值nullptr(C11)4.1 C98中的指针空值 所属专栏:C初阶 一、内联函数 1.1概念 以inline修饰的函…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
