网络编程(12): TCP重传、滑动窗口、流量控制、拥塞控制
1、TCP重传机制
通过序列号和确认号确保可靠传输,当发送端发送数据给接收到,接收端会返回一个确认号,表示收到消息了
- 超时重传:没有在指定时间内收到
ACK
报文- 超时重传的两种可能:数据包丢失、确认包丢失
- 超时重传时间
RTO
:RTO
较大:重发就变慢了,丢包之后需要半天才能重发,效率低RTO
较小:可能没有丢包,还在等待ACK过程中,就重发了,会导致网络拥塞,进而导致更多的超时重发- 所以
RTO
需要略大于报文往返的时间RTT
(数据发送到接收到ACK的时间差)
- 由于网络波动问题,
RTT
可能不是固定的,所以RTO
对应也不是固定的 - 一般超时重传一次,下一次超时重传的间隔会加倍,避免网络环境差的频繁发送
- 快速重传:
超时重传的问题
:重传周期可能很长(时间会加倍),快速重传可以解决这个问题,以数据为驱动作为重传- 发送了数据包
seq1
~seq5
,- 发送端发送
seq1
,接收端回复ack=2
,表示接收到包1 seq2
丢失- 发送端连续发送
seq3
~seq5
,接收端会重复返回ack=2
- 连续三次
ack=2
,触发快速重传
,重复seq2
- 由于接收到了
seq3
~seq5
,发送端会返回ack=6
- 发送端发送
- 快速重传只解决了超时问题,但是还有一个问题:重传的时候重传一个还是所有数据包
- 因为如果只重传一个,当有两个数据包丢失的时候,需要判断两次返回的ack(三次重复),来进行单包重传,效率低
- 如果重传所有,就会有多余的包被重新发送,无用功
- SACK:选择性确认,可以知道哪些数据丢失了
- 需要
TCP
头部选项
字段中,添加一个SACK
,可以将已接收到的数据的信息发送给发送方,发送方就知道了哪些数据丢失了,从而只发送丢失的数据 - 在快速重传的基础上,发送方收到三次相同的ack报文,触发快速重传机制,通过
SACK
信息可以知道哪段数据丢失了,只对丢失的数据重传
- 需要
D-SACK
:通过SACK
告诉发送端哪些数据被重复接收了- 可以让发送端知道是包丢失,还是ACK包丢失了
- 可以知道发送的数据包是不是被网络延迟了
- 可以知道网络中是不是把发送端的数据包给复制了
- 小结:
- 如果数据包丢失或者ACK包丢失,超过一定时间会触发超时重传,超时时间
RTO
略大于RTT
时间(发送数据到接收ACK包的时间间隔) - 为了解决超时等待的时间,提高效率,就有了快速重传,当有一个包丢失的时候,可以通过判断重复的ack进行快速重传,通过在TCP头部的选项字段里面添加SACK,就可以知道哪些包是丢失的,从而只重传丢失的包
- 如果在
ACK
包丢失,导致的超时重传,发送端接收到接收端SACK
从而知道收到了重复数据,这个SACK
就是D-SACK
,如果一个包由于网络问题导致的快速重传,也可以通过D-SACK
来进行判断
- 如果数据包丢失或者ACK包丢失,超过一定时间会触发超时重传,超时时间
2、TCP滑动窗口
TCP每次发送数据都要进行确认应答,当上一个包收到应答了再发下一个
- 如果是一问一答的形式,则数据包往返的时间周期越长,通信效率就越低
- 为了解决上面的问题,就有窗口概念,
- 可以指定窗口大小,窗口大小是不需要等待确认应答,可以继续发送数据的最大值
- 窗口是内核里面开辟的缓存区,需要保留发送的数据,只有收到应答才会从缓冲区中删除
- 在
TCP头部
可以指定窗口大小,发送端会根据ACK
返回的窗口大小,来发送数据,从而保证对端可以正常接收数据,所以窗口大小是由接收端决定的
- 发送端的窗口:
- 有两个绝对指针:一个指向没有收到ack的第一个字节的序列号, 一个指向窗口中可用空间的第一个字节的序列号
- 会根据ACK报文中的窗口大小进行调整,因为应用层不一定及时收数据
- 此外,如果发送端窗口满了,没有及时收到
ACK
,就不能在应用层进行发送数据,如果序列号较前的收到ack,窗口会向右移动,存在可发空间,应用层可以继续拷贝发送数据
- 接收端的窗口:可以接收发送端发送的数据量,一次能处理的数据量
- 只有一个绝对指针,指向期望对端发送来的下一个字节的序列号
- 窗口里面是还没进行确认的数据,也就是还没收到的数据,但是可以接收的数据大小
- 发送端窗口约等于接收端窗口,因为传输存在延迟,不一定及时调整窗口大小,所以是约等于
- 小结:
- 三次握手确定窗口大小,接收端能接收多少数据,发送端根据接收端数据进行调整,去发送数据,在发送端窗口大小内,发送端可以一直发,并等待接收端返回ack确认号来发送窗口移动,每次ack报文都会携带窗口大小,可能会改变;
3、TCP流量控制
利用滑动窗口实现流量控制,发送端不能一股脑的发过去,如果对方处理不过来就会触发重传机制
- 流量控制:发送方 根据 接收方的实际接收能力发送数据,也就是接收端滑动窗口的大小
- TCP内核缓冲区和滑动窗口的关系:缓冲区大小会影响窗口大小
- 应用层不及时收取数据,会导致窗口变小:
- TCP滑动窗口(指针实现)是处于TCP缓冲区中间的,如果接收端接收到数据并返回ACK,但是应用层没有及时收取,当缓冲区内存不够,可能会导致滑动窗口变小,当窗口大小变成0,就发生了窗口关闭
- 系统资源减少,会导致缓冲区变小:
- 如果用户空间没有及时读取缓冲区数据,并且接收缓冲区由于系统资源突然变小,发送端来不及调整,会导致数据丢包现象,这是因为先减少缓冲区再收缩窗口
- 所以不允许同时减少缓冲又收缩窗口,而先收缩窗口后一段时间再减少缓冲,从而避免丢包
- 应用层不及时收取数据,会导致窗口变小:
- 窗口关闭:
- 窗口大小为0的情况,就会阻止发送端发送数据,直到大小变成非0
- 如果接收端窗口变成非0,会通过发送携带窗口大小的ACK报文,如果ACK报文丢失,发送端会一直等待,造成死锁问题
- 如何避免死锁问题:当窗口关闭,就会启动一个持续计时器,如果超时就会发送一个
窗口探测报文
,接收端收到这个报文,就会返回一个携带当前窗口大小的ACK报文,如果窗口依旧为0,就会重启持续计时器
- 糊涂窗口综合症
- 接收端太忙,会导致发送端的窗口越来越小,到最后只有接收端腾出字节空间,发送端就会马上发送,但是TCP/IP包头就有40字节,有数据就传输的话,开销太大了
- 导致的原因是:
- 接收端告知小窗口大小
- 发送端发送小数据
- 如何避免:
- 接收方不告知小窗口,窗口小于某个值就发送窗口为0的ACK,阻止对端发送数据
- 发送发避免发送小数据,开启Nagle算法,避免小包发送
- Nagle算法思想,延时处理,满足下面一个条件即可:
- 窗口大小>=MSS并且数据大小>=MSS
- 收到前一个数据的ack报文
- 一般需要搭配 不通知小窗口给发送方+开启Nagle算法才能避免糊涂窗口综合症
4、TCP拥塞控制
-
流量控制:是为了避免,发送端 数据填满 接收端的缓存,但是流量控制并不知道网络中发送的情况
-
网络拥塞:网络发生拥堵的时候,继续发送大量数据包,就可能导致数据包延时、丢失等情况,TCP就会重传数据,一旦重传就会导致网络更加拥堵,从而不断恶性循环
-
拥塞控制:避免发送方的数据填满整个网络,并且为了调节发送数据的量,定义了一个
拥塞窗口(cwnd)
的概念 -
拥塞窗口(cwnd):是发送方维护的一个状态变量,会根据网络的拥塞程度进行变化,滑动的发送窗口=min(滑动的接收窗口,拥塞窗口),当网络没有出现拥塞,
cwnd
窗口就会越大,当网络出现拥塞,cwnd
就会越小 -
如何判断网络拥塞:发送方没有在指定时间接收到ACK应答报文,也就是发送超时重传,就会认为网络出现拥塞了
-
拥塞控制主要是四算法:
- 慢启动:(指数增长)
- TCP建立连接后,一点点点提高数据包发送的数量,发送端没收到一个ACK,拥塞窗口
cwnd
的大小就会+1; - 存在一个慢启动门限
ssthresh
,如果cwnd
<ssthresh
使用的就是慢启动算法,如果cwnd
>=ssthresh
,就使用拥塞避免算法;ssthresh
一般大小为65535字节
- TCP建立连接后,一点点点提高数据包发送的数量,发送端没收到一个ACK,拥塞窗口
- 拥塞避免:
- 没收到一个ACK,
cwnd
增加1/cwnd
,是为了确保cwnd
的线性增长 - 如果一直保持增长,网络就会慢慢进入拥塞状态,从而出现了丢包现象
- 如果触发了重传机制,就会进入拥塞发生算法
- 没收到一个ACK,
- 拥塞发送:
- 发生重传(超时、快速)的时候就会进入拥塞发生算法
- 超时重传的拥塞发生:
ssthresh
会设置为cwnd/2
,并且cwnd
会回复为初始值,linux的初始值是10(10个MSS);- 设置完
ssthresh
和cwnd
之后,会重新开始慢启动; - 这种方式下来的拥塞发生太激进了,容易造成网络卡顿
- 快速重传的拥塞发生:
- 设置
cwnd
为cwnd/2
,再设置ssthresh
为cwnd
- 设置完之后,会进入
快速回复算法
- 设置
- 快速回复:
- 当发生快速重传的时候,表示网络不是太糟糕,一般快速回复和快速重传同时使用
- 进入快速回复前,
cwnd
和ssthresh
都全部设置完了 快速回复
:cwnd
=ssthresh+3
,3表示接收到了三个数据包- 重传丢失的数据包;
- 如果再收到重复的
ACK
,cwnd
就+1 - 如果收到的是新的ACK,表示网络没问题了,则将cwnd设置为ssthresh,进入拥塞避免状态;
- 慢启动:(指数增长)
-
拥塞控制算法过程:
- 从TCP三次握手建立连接开始,发送端开始慢启动,没收到一个包的ACK,拥塞窗口就会+1,如果达到阈值,就会进入拥塞避免算法,每收到一个包的ACK,拥塞窗口就会增加窗口的倒数,从而保证拥塞窗口的线性增加
- 当遇到丢包的情况,就判断为网络拥塞,从而重复重传机制,进入拥塞发送算法,根据重传机制的不同,拥塞发送算法也会不同
- 超时重传,sthresh=cwnd/2,并且cwnd=初始值,重新重慢启动开始
- 快速重传,cwnd=cwnd/2,ssthresh=cwnd,开启快速回复
- 快速回复:先是设置cwnd=ssthresh+3,并重传丢失数据包,如果依旧重复收到相同的ACK,就会重复触发快速重传和快速回复,如果收到的是新的数据包,则进入拥塞避免状态。
参考文章:小林coding
相关文章:
网络编程(12): TCP重传、滑动窗口、流量控制、拥塞控制
1、TCP重传机制 通过序列号和确认号确保可靠传输,当发送端发送数据给接收到,接收端会返回一个确认号,表示收到消息了 超时重传:没有在指定时间内收到ACK报文 超时重传的两种可能:数据包丢失、确认包丢失超时重传时间RT…...

Docker安装RabbitMQ服务端
使用docker安装RabbitMQ服务端 1、搜索镜像 docker search rabbitmq2、拉取镜像 默认拉取最后一个版本,可以在后面加版本号拉取指定版本 docker pull rabbitmq 3、运行镜像 docker run -d --hostname my-rabbit --name rabbit -p 15672:15672 rabbitmq4、查看…...

vueuse常用方法
useDateFormat 时间格式化 <script setup lang"ts">import { useNow, useDateFormat } from vueuse/coreconst formatted useDateFormat(useNow(), YYYY-MM-DD HH:mm:ss)</script><template><div>{{ formatted }}</div> </templa…...

选择大型语言模型自定义技术
推荐:使用 NSDT场景编辑器 助你快速搭建可二次编辑器的3D应用场景 企业需要自定义模型来根据其特定用例和领域知识定制语言处理功能。自定义LLM使企业能够在特定的行业或组织环境中更高效,更准确地生成和理解文本。 自定义模型使企业能够创建符合其品牌…...
算法概述-Java常用算法
算法概述-Java常用算法 1、算法概念2、算法相关概念3、算法的性能评价4、算法应用归纳 1、算法概念 广泛算法定义:算法是模型分析的一组可行性的、确定的和有穷的规则。 经典算法特征:有穷性、确切性、输入、输出和可行性。 常用的算法包括递推、递归、穷…...

CCLINK转MODBUS-TCP网关cclink通讯接线图 终端电阻
大家好,今天我们要聊的是生产管理系统中的CCLINK和MODBUS-TCP协议,它们的不同使得数据互通比较困难,但捷米JM-CCLK-TCP网关的出现改变了这一切。 1捷米JM-CCLK-TCP是一款自主研发的CCLINK从站功能的通讯网关,它的主要功能是将各种…...

香蕉派 BPI-P2 Pro采用RK3308芯片,512M内存,8G存储,支持PoE供电
Banana Pi BPI-P2 pro(Armsom pro)是一款基于瑞芯瑞(Rockchip) RK3308B-S芯片的开发板。采用高性能4核ARM Cortex-A35处理器,512M RAM内存。和8G eMMC板载存储,支持PoE网线供电功能。芯片具有丰富的接口,如I2S、PCM、TDM、I2C、UART、SPDIF、…...

「隐语小课」拆分学习之“水平拆分学习”
一、引言 拆分学习是 2018 年由 MIT 最先提出的分布式算法。本文结合该领域的相关英文文献,介绍水平拆分学习的基本方法,同时还将对比拆分模型与中心化模型、联邦模型在不同条件下模型效率和准确性。拆分学习作为主流的隐私计算学习范式之一,…...
WPF--关于Action事件小结
WPF--关于Action事件小结 1.需要类实例去调用事件建立订阅关系 public event Action<int, object> MaintainEvent; new GP1().MaintainEvent NormalCmdAction; 2.static用处--在不便实例的时候,可以直接由类调用 public static event Action<int, objec…...

创建一个 React+Typescript 项目
接下来 我们来一起探索一下用TypeScript 来编写react 这也是一个非常好的趋势,目前也非常多人使用 那么 我们就先从创建项目开始 首先 我们先找一个 或者 之前创建一个目录 用来放我们的项目 然后 在这个目录下直接输入 例如 这里 我想创建一个叫 tsReApp 的项目…...

Java课题笔记~ 数据提交的方式
前四种数据注入的方式,会自动进行类型转换。但无法自动转换日期类型。 (1)单个数据(基本数据类型)注入 在方法中声明一个和表单提交的参数名称相同的参数,由框架按照名称直接注入。 (2&#x…...
VUE3给页面添加按钮事件
在Vue 3中,可以通过使用setup函数来添加事件和自定义逻辑。下面是一个示例代码,演示了如何添加页面上的altb事件 <template><div><p>Press Alt B to trigger the event!</p></div> </template><script setup&g…...
基于centos7.9通过nginx实现负载均衡以及反向代理
摘要:负载均衡: 负载均衡是一种技术,用于在多个服务器之间分发传入的网络流量,以平衡服务器的负载,提高系统的可用性和性能。当您有多台服务器时,您可以使用负载均衡将请求分发到这些服务器上,从…...

前端原生写自定义旋转变换轮播图
html部分: <div class"banner_box"><div class"swiperWrapper" v-show"bannerList.length>0"><div class"swiper-item" :id"swiperSlide${index}" :class"{active:index0,next:index1,pr…...

linux tomcat server.xml 项目访问路径变更不生效
如果想改成默认的127.0.0.1:8080 访问项目 先确定更改的作用文件 server.xml 的 host:appBase 标签 默认找到appBase webapps 下的war包,并解压,解压后的appname为访问路径 也就变成了 127.0.0.1:8080/appname host:Context:path 标签 appBase的 优先…...
介绍原型模式:快速构建和复制对象的设计模式
经过瀑布模式之后,我们不禁想要用模型解决更多的问题,最重要的就是不再单向行径。 由此,介绍 原型模式, 所谓原型,就是我们有一个框架或者初始角色。我们可以根据项目的不同,对它进行不同的修改࿰…...

Unity的TimeScale的影响范围分析
大家好,我是阿赵。 这期来说一下Unity的TimeScale。 一、前言 Unity提供了Time这个类,来控制时间。其实我自己倒是很少使用这个Time,因为做网络同步的游戏,一般是需要同步服务器时间,所以我比较多是在使用System.Date…...

爬虫逆向实战(五)--猿人学第三题
一、数据接口分析 主页地址:猿人学第三题 1、抓包 通过抓包可以发现数据接口是api/match/3 2、判断是否有加密参数 请求参数是否加密? 无请求头是否加密? 无响应是否加密? 无cookie是否加密? 无 二、发送请求 …...

[虚幻引擎] UE使用虚拟纹理在模型上显示挖空效果
此教程是记录如在UE中使用虚拟纹理,实现模型挖洞的效果。 1. 新建项目,开启项目支持虚拟纹理并并重启。 2. 新建一个基础关卡 3. 拖动“运行时虚拟纹理体积” 进入场景,并把体积修改变大,以可以完全包括到地板。 4. 创建一个虚拟纹…...
vue3中reactive和ref的比较
1.reactive和ref函数的共同作用是什么? 用函数调用的方式生成响应式数据 2. reactive vs ref? 1.reactive不能处理简单类型的数据 2.ref参数类型支持更好但是必须通过.value访问修改 3.ref函数的内部实现依赖于reactive函数 3. 在实际工作中推荐使用哪个? …...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...