TCP详解之拥塞控制

2023-05-16

概述

  TCP模块还有一个重要任务,就是提高网络利用率,降低丢包率,并保证网络资源对每条数据流的公平性,这就是所谓的拥塞控制。
  拥塞控制的四个部分:慢启动、拥塞避免、快速重传、快速恢复。拥塞控制算法在Linux下有多种实现,比如reno、vegas和cubic算法,他们部分或全部实现了上述四个部分。/proc/sys/net/ipv4/tcp_congestion_control文件指示机器当前使用的拥塞控制算法。
  拥塞控制的最终受控变量是发送端向网络一次连续写入的数据量(收到第一个确认数据报之前),我们称之为SWND(Send Window,发送窗口)。发送端最终是以TCP报文段来发送数据,所以SWND限定了发送端能连续发送的TCP报文段数量。这些TCP报文段的最大长度(仅指数据部分)称为SMSS(Sender Maximun Sefment Size,发送者最大段大小),其值一般等于MSS(最大报文长度)。
  发送端需要合理地选择SWND大小,如果SWND太小,会引起明显的网络延迟;反之太大,会导致网络拥塞。接收方可通过其接受通告窗口(RWND)来控制发送端的SWND,但这显然不够,所以发送端引入了一个称为拥塞窗口(Congestion Window,CWND)的状态变量。实际的SWND值是RWND(16位接收通告大小)和CWND(拥塞窗口)的较小值。
在这里插入图片描述
  如图所示,拥塞控制的输入和输出是一个闭环反馈控制。

慢启动和拥塞避免

  TCP连接建立好之后,CWND将被设置成初始值IW(Initial Window),其大小为2-4个SMSS。新的Linux内核提高了该初始值,以减小传输滞后。此时发送端最多可以发送IW字节的数据。此后发送端每收到接收端的一个确认,其CWND就按照下列公式增加:
在这里插入图片描述
  其中N是此次确认中包含的之前未被确认的字节数。这样一来,CWND将按照指数形式扩大,这就是所谓的慢启动。慢启动算法的理由是:TCP模块刚开始发送数据时并不知道网络的实际情况,需要一种试探的方式平滑地增加CWND的大小。
  如果不施加其他手段,慢启动必然使得CWND很快膨胀,并最终导致网络拥塞。因此TCP拥塞控制中定义了另一个重要的状态变量:慢启动门限(ssthresh)。当CWND的大小超过该值时,TCP拥塞控制将进入拥塞避免阶段。
  拥塞避免算法使得CWND按照线性方式增加,从而减缓其扩大。拥塞避免算法有如下
两种实现方式
  1.每个RTT(一个连接的往返时间,即数据发送时刻到接收到确认的时刻的差值)时间内按照上图公式计算新的CWND,而不论该RTT时间内发送端收到多少个确认。
  2.每收到一个对新数据的确认报文段,就按照CWND+=SMSS*SMSS/CWND来更新CWND。
下图粗略地描述了慢启动和拥塞避免发生的时机和区别。图中以SMSS为单位来显示CWND(实际是以字节为单位的),以次数为单位来显示RTT,为了方便讨论问题,此外,我们假设当前的慢启动门限是16SMSS大小(实际比这大得多)。

在这里插入图片描述


拥塞发生时(可能发生在慢启动阶段或者拥塞避免阶段)拥塞控制的行为。
发送端判断拥塞发生的依据有如下两个:
在这里插入图片描述
在这里插入图片描述
  其中FlightSize是已经发送但未收到确认的字节数。这样调整后,CWND将小于SMSS,那么也必然小于新的慢启动门限值,故而拥塞控制再次进入慢启动阶段。

超时重传

  TCP服务必须能够重传超时时间内未收到确认的TCP报文段。为此,TCP模块为每一个TCP报文段都维护一个重传定时器,该定时器在TCP报文段第一次被发送时启动。如果超时时间内未收到接受方的应答,TCP模块将重传TCP报文段并重置定时器。下一次的超时时间和总的重传次数是TCP的重传策略。
  TCP报文段重传的时间间隔为0.2s,0.4s,0.8s,1.6s,3.2s。可见TCP一共进行五次重传,每次重传超时时间增加一倍(和TCP超时重连策略相似)。在五次重传均失败的情况下,底层的IP和ARP开始接管,直到telnet客户端放弃连接为止。
  /proc/sys/net/ipv4/tcp_retries1指定在底层IP接管之前TCP最少执行的重传次数,默认为3,/proc/sys/net/ipv4/tcp_retries2指定连接放弃前TCP最多可以执行的重传次数,默认为15。
  虽然超时会导致TCP报文重传,但TCP报文段的重传可以发生在超时之前,即快速重传。

快速重传和快速恢复

  在很多情况下,发送端都可能接收到重复的确认报文段,比如TCP报文段丢失,或者接收端收到乱序TCP报文段并重排之等。拥塞控制算法需要判断当收到重复的确认报文段时,网络是否真的发生了拥塞,或者说TCP报文段是否真的丢失了。
  当发送端如果连续收到3个重复的确认报文段,就认为是拥塞发生了。然后它启用快速重传和快速恢复算法来处理拥塞。过程如下:
1.当收到第三个重复的确认报文段时,按照ssthresh=max(FlightSize/2,2SMSS)计算ssthresh,然后立即重传丢失的报文段,并按照CWND=ssthresh+3SMSS来设置CWND。
2.每次收到一个重复的确认时,设置CWND=CWND+SMSS,此时发送端可以发送新的TCP报文段(如果新的CWND允许的话)。
3.当收到新数据的确认时,设置CWND=ssthresh(是新的慢启动门限值,由第一步计算得到)。
  快速重传和快速恢复之后,拥塞控制将恢复到拥塞避免阶段,这一点由第三步操作可得知。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TCP详解之拥塞控制 的相关文章

  • Spring Integration TCP - 在发送数据之前启动消息握手

    我正在使用 MessagingGateway 将数据发送到服务器 我为出站网关配置了 AbstractClientConnectionFactory 和 ServiceActivator 为了将数据发送到我的服务器 我需要在启动连接时发送握
  • 如何监控 TCP 连接的 cwnd 和 ssthresh 值? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我希望在通过套接字连接发送或接收数据包时确定这些值 有没有现有的工具可以做到这一点 The ss http linux die net m
  • Boost ASIO:服务器如何知道客户端是否仍然连接?

    我在用boost asio对于服务器 客户端应用程序 服务器一次只接受一个连接 我想知道服务器验证客户端是否仍然连接的最佳方法是什么 这样做的目的是我希望能够知道客户端是否崩溃 以便我可以重新开始侦听新的连接尝试 在我的应用程序中 我使用以
  • 为什么在数据包输入时 skb_buffer 需要跳过 20 个字节才能读取传输缓冲区?

    我正在 Linux 中编写一个网络模块 我发现只有在从 skb 缓冲区跳过 20 个字节后才能提取 tcp 标头 即使 API 是 skb transport header 其背后的原因是什么 有人可以详细解释一下吗 传出数据包不需要同样的
  • TCP Socket无连接超时

    我打开一个 TCP 套接字并将其连接到网络上其他位置的另一个套接字 然后我就可以成功发送和接收数据 我有一个计时器 每秒向套接字发送一些内容 然后 我通过强行断开连接 在本例中拔出以太网电缆 来粗暴地中断连接 我的套接字仍然报告它每秒都在成
  • 通过 TCP 客户端套接字接收数据时出现问题

    我正在尝试用 C 语言编写一个 TCP 客户端程序 客户端将在其中启动 连接到服务器 然后它会发送一些信息 然后监听它收到的信息并做出相应的反应 我遇到麻烦的部分是持续聆听 这是我所拥有的 while 1 numbytes recv soc
  • 什么是消息边界?

    什么是 消息边界 在以下情况下 TCP 和 UDP 之间的区别之一是 UDP 保留消息 边界 我理解之间的区别TCP and UDP 但我不确定的定义 消息边界 由于 UDP 在每个单独的数据包中包含目的地和端口信息 因此是否可以为消息提供
  • Scapy 不需要的 RST TCP 数据包

    为了理解TCP是如何工作的 我尝试伪造自己的TCP SYN SYN ACK ACK 基于教程 http www thice nl creating ack get packets with scapy http www thice nl c
  • Go TCP 读取是非阻塞的

    我正在尝试用 Go 创建服务器和客户端 我已经成功地与服务器和客户端进行通信 但我遇到的问题是golang中的TCP读取是非阻塞的 我想知道 golang 中的读取是否有可能像 C 中的读取一样阻塞 谢谢 EDIT 这是服务器的源代码 fu
  • 是否可以通过互联网在两个移动设备 (iPhone) 之间连接套接字?

    是否可以通过互联网在两个移动设备 iPhone 之间连接套接字 我正在尝试发现每个设备的IP并直接连接 我知道可以使用 Bonjour 来完成 但这只适用于本地网络 我需要通过互联网在两个设备之间建立高速连接 Thanks 如果你有两个 I
  • Python套接字模块:Recv()数据响应被切断

    解释 我目前正在尝试使用 python 脚本控制智能电源板 为了实现这一点 我使用了带有套接字模块的 TCP 连接 大约 75 的情况下 我会得到我正在寻找的响应 数据 并且一切都运行良好 然而 大约 25 的情况下 响应会以完全相同的长度
  • 在 Golang Server 中接受持久的 tcp 连接

    我正在尝试使用 Go 并且想创建一个 TCP 服务器 我可以通过 telnet 访问该服务器 发送命令并接收响应 const CONN HOST localhost CONN PORT 3333 CONN TYPE tcp func mai
  • 两个http请求可以合并在一起吗?如果可以的话,nodeJS服务器如何处理呢?

    昨天我做了一些关于 NodeJS 的演讲 有人问我以下问题 我们知道nodeJS是一个单线程服务器 多个请求是 到达服务器并将所有请求推送到事件循环 如果什么 两个请求同时到达服务器 服务器将如何处理 处理这种情况 我猜到了一个想法并回复如
  • C# Socket.receive连续接收0字节且循环中不阻塞

    我正在尝试用 C 编写一个最简单的多线程 TCP 服务器 它接收来自多个客户端的数据 每次连接新客户端时 都会建立套接字连接 并将套接字作为参数传递给新类函数 之后运行 while 循环并接收数据 直到客户端连接为止 这里的问题是 sock
  • 为什么 TCP 段中的 SYN 或 FIN 位会占用序列号空间中​​的一个字节?

    我试图理解这种设计背后的基本原理 我浏览了一些 RFC 但没有发现任何明显的东西 这并不是特别微妙 这样 SYN 和 FIN 位本身就可以被确认 因此如果丢失则可以重新发送 例如 如果连接关闭而没有发送更多数据 那么如果 FIN 没有发送任
  • iOS 上的多个 HTTP 请求与单个 TCP 连接

    我正在开发一个 iPhone 应用程序 它使用我控制的基于 Web 的 API 连接到持续打开的 TCP 端口并通过 TCP API 发出请求 或者为我想要获取的所有数据发出新的 HTTP 请求 会更快或更高效吗 我认为差异可以忽略不计 但
  • 如何强制关闭 TcpListener

    我有一个通过 tcpListener 进行通信的服务 问题是当用户重新启动服务时 抛出 地址已在使用 异常 并且服务在几分钟左右无法启动 有没有办法告诉系统终止旧连接 以便我可以打开一个新连接 我不能只使用随机端口 因为服务无法通知客户端端
  • 使用 boost 异步发送和接收自定义数据包?

    我正在尝试使用 boost 异步发送和接收自定义数据包 根据我当前的实现 我有一些问题 tcpclient cpp include tcpclient h include
  • UWP 无法在两个应用程序之间创建本地主机连接

    我正在尝试在两个 UWP 应用程序之间设置 TCP 连接 当服务器和客户端在同一个应用程序中运行时 它可以正常工作 但是 当我将服务器部分移动到一个应用程序并将客户端部分移动到另一个应用程序时 ConnectAsync 会引发异常 服务器未
  • Erlang gen_tcp 连接问题

    简单的问题 这段代码 client gt SomeHostInNet localhost to make it runnable on one machine ok Sock gen tcp connect SomeHostInNet 56

随机推荐

  • Html5下载功能实现

    downloader模块管理网络文件下载任务 xff0c 用于从服务器下载各种文件 xff0c 并支持跨域访问操作 通过plus downloader获取下载管理对象 Downloader下载使用HTTP的GET POST方式请求下载文件
  • 卡尔曼滤波总结(KF、EKF、UKF)

    1 马尔科夫 参考 xff1a https zhuanlan zhihu com p 489239366 2 协方差矩阵 1 xff09 对于一个样本集合S xff0c 如果每个样本是一个n维空间中的一个列向量 xff0c 则使用协方差矩阵
  • Centos7搭建Squid代理服务器

    Centos7搭建Squid代理服务器 sumu s home 1 无需验证版 http 1 1 安装 yum install squid 1 2 修改配置文件 打开文件 vim etc squid squid conf修改 http ac
  • Python 3.6解决报错:'NoneType' object has no attribute 'decode'的办法

    for repo dict in repo dicts names append repo dict 39 name 39 plot dict 61 39 value 39 repo dict 39 stargazers count 39
  • 手把手教你实现ROS依赖任意第三方库+lpsolve求解整数线性规划问题为例

    How to link dynamic libraries use third party libraries in ROS lpsolve solver as examples 喜欢的话请关注 xff0c 欢迎github 给个小星星 g
  • UCOS-III

    一 UCOSIII 简介 UCOSIII 是一个可裁剪 可固化 可剥夺 的多任务系统 xff0c 没有任务数目的限制 xff0c 是 UCOS 的第三代内核 xff0c UCOSIII 有以下几个重要的特性 xff1a 可剥夺多任务管理 x
  • 【Python】词频统计(written in python and Mapreduce)

    一 利用Python进行词频统计 xff08 一 xff09 计算机等级考试中常用的方法 首先是一个比较标准的考试中使用的方法 xff0c 针对英文文本 xff1a span class token keyword def span spa
  • 数据处理技巧(5):MATLAB 读取txt中的数据

    全是数字的类型 txt 的数据是有数字的 xff0c 如下图 xff1a 读取结点坐标 xff0c 保存在 NodeCoor 数组当中 xff0c 共1331行3列 filename span class token operator 61
  • 基于51单片机的模拟自动感应门 系统protues仿真

    硬件设计 xff08 末尾附文件 xff09 代码设计 include lt reg51 h gt 调用头文件 define uchar unsigned char 宏定义 define uint unsigned int 宏定义 端口定义
  • linux测试程序

    stresslinux super pi prime mprime nbench cpuburn gamut mersenne prime stress cpu burn in memtester memtest86 memtest86 4
  • mysql 删除多余0的问题

    0 43 CAST 字段 AS CHAR 别名 可加可不加
  • 三维点沿指定向量方向到平面的距离计算方法及C++代码实现

    设平面外一点为P p1 p2 p3 xff0c 指定的方向向量为d 61 d1 d2 d3 xff0c 平面Q方程为Ax 43 By 43 Cz 61 D xff0c 设系数ABC已经归一化 xff0c 则其法向量为n 61 A B C 则
  • ubuntu使用proxychains给终端设置代理

    有时 xff0c 我们需要下载一些国外网站上的东西 xff0c 如果用国内网络直接下载的话 xff0c 往往是连接不上的 或者有时下载一个东西速度很慢 xff0c 这都是因为国内网络限制的问题 xff0c 大大影响了我们的工作效率 解决方法
  • int为什么占4个字节?一个字节为什么是8位?

    不知道大家有没有思考过这样的问题 xff0c 一个字节为什么是8位呀 xff0c 也许还有小伙伴不知道我说的这些是什么 xff0c 没关系往下看 第一个解释 xff08 历史 xff09 是IBM为System 360设计了一套8位EBCD
  • K8S之kubectl命令详解及示例

    目录 1 查看类命令 2 操作类命令 3 进阶命令操作 4 kubectl replace 重启pod的四种方法 5 kubectl语法 1 查看类命令 获取节点和服务版本信息 kubectl get nodes 获取节点和服务版本信息 x
  • ROS运动规划学习五---global_planner

    文章目录 前言一 global planner功能包结构二 planner core1 执行过程2 calculatePotentials 3 getPlanFromPotential 总结 前言 本节将学习ROS中的全局规划期global
  • ROS自定义消息---发布数组和整型数据

    ROS自定义消息 数组和整型数据 前言一 ROS中的消息数据格式二 自定义话题消息1 新建msg文件2 编写发布者和接收者程序 总结 前言 ROS自带的消息格式已经包含一维数组 xff0c 有时候我们需要定义多维数组 xff0c 以及混合数
  • Markdown中的公式、字母表示汇总

    Markdown中的公式 字母表示汇总 1 常用希腊字母表2 数学公式 最近几个月打了很多Markdown公式 xff0c 隔一段时间就会忘一些表示方式 xff0c 还不如在这里慢慢汇总记录 xff0c 以后要用的时候来查就行了 xff01
  • CMake项目中神器:CMakeLists.txt

    首次接触 CMake xff0c 见识了 CMakeLists txt 的强大后 xff0c 赶紧整理出来分享一下 参考资料 xff1a Cmake 3 6 W3Cschool参考手册 本文讲述了一个 CMake 项目 xff0c 在从单文
  • TCP详解之拥塞控制

    概述 TCP模块还有一个重要任务 xff0c 就是提高网络利用率 xff0c 降低丢包率 xff0c 并保证网络资源对每条数据流的公平性 xff0c 这就是所谓的拥塞控制 拥塞控制的四个部分 xff1a 慢启动 拥塞避免 快速重传 快速恢复