传输层协议TCP ( 下 )

文章目录

  • 前言
  • 序号与确认序号
  • 超时重传
    • RTO
    • Jacobson算法
    • 内核中超时时间的计算
  • 滑动窗口
    • 滑动窗口
    • 延迟应答
    • 流量控制
  • 拥塞控制
      • 慢启动
      • 拥塞避免
      • 快重传
      • 快速恢复
  • 保活机制
  • 参考资料


前言

  TCP(Transmission Control Protocol,传输控制协议)是互联网最重要的协议之一,为应用层提供可靠的、面向连接的数据传输服务。它广泛应用于 HTTP、FTP、SMTP 等协议中,保障数据能够准确、有序地到达目标设备。本文将主要介绍TCP其他保证可靠性机制

序号与确认序号

​ TCP是面向字节流的协议,数据在传输时并不以数据包为单位,而是以字节为单位进行传输。每个 TCP 数据段都会携带一个序号,指示数据段中第一个字节的位置, 如果将字节流看作在两个应用程序间的单向流动,则可以看作 TCP 用序号对每个字节进行计数。序号是32 bit的无符号数,序号到达 23^2-1后又从0开始, 由于IP协议是不可靠无序的, 不同的 IP 报文可能通过不同的路由到达目标主机的顺序不同, TCP 要保证可靠性, 就需要对这些乱序的报文进行排序, TCP 报文中的 32位序号就是用于报文排序

​ 首部 32位确认序号用于确保数据传输的可靠性和顺序性。它是接收端告诉发送端,在这个确认序号之前的报文都收到了,

例如:如果发送方发送了1000 - 1099 和1100 - 1199的数据, 如果接收端已经成功接收到这两个报文的数据,那么它的确认序号将是 1200,表示1200以前的报文都收到了, 如果发送丢包, 比如接收方只接收到了 1000 - 1099 的数据, ,那么它的确认序号将是 1100, 如果是前一个报文1000 - 1099 丢失后一个报文收到, 根据确认序号的意义, 此时确认序号不可能是1100和1200, 确认序号将是1000

超时重传

​ TCP 提供可靠的运输层。它使用的方法之一就是确认从另一端收到的数据。但数据和确认都有可能会丢失。TCP 通过在发送时设置一个定时器来解决这种问题。如果当定时器到期时还没有收到确认,它就重传该数据

RTO

​ 超时重传机制中的关键是 重传超时时间(Retransmission Timeout,RTO),即发送方等待接收方确认的最大时间。RTO的选择是动态的,不是一个固定值,而是根据网络的当前状况来调整

  1. 《TCP-IP详解卷1:协议》中表示可以通过一下公式估计
RTO = A + 4D
  1. RFC-793 3.7 给出的计算方法为
SRTT = (ALPHA * SRTT) + ((1 - ALPHA) * RTT)
RTO = min[UBOUND, max[LBOUND, (BETA * SRTT)]]
  • 其中,UBOUND是超时的上限(例如1分钟),LBOUND是超时的下限(例如1秒),ALPHA是平滑因子(例如0.8到0.9),BETA是延迟方差因子(例如1.3到2.0)。
  1. RFC-1122 4.2.3.1 指出RFC-793中建议的计算重传超时的算法现在被认为是不充分的, 并重新给出计算

主机TCP必须实现Karn算法和Jacobson算法来计算重传超时(“RTO”)。

  • Jacobson算法用于计算平滑的往返时间(“RTT”),它包括一个简单的方差度量[TCP:7]。
  • Karn算法用于选择RTT测量,确保不明确的往返时间不会破坏平滑往返时间的计算[TCP:6]。

该实现还必须包括“指数回退”机制,用于相同段的连续RTO值计算。SYN段的重传应使用与数据段相同的算法。

Jacobson算法

SRTT = aRTT + (1-a)SRTT
RTTVAR  = (1-b)RTTVAR + b|SRTT-RTT|
RTO=SRTT+max(G,4×RTTVAR)
  • a 是平滑因子,通常设定为7/8
  • b 是另一种平滑因子,通常设置为 0.25

RFC-1122 4.2.3.1 指出:

以下值应当用于初始化新连接的估算参数

(a) RTT = 0秒。

(b) RTO = 3秒。(平滑方差应初始化为能够产生此RTO的值)。

RTO的推荐上下限已知在大规模互联网中不足以满足要求。下限应以秒的分数来衡量(以适应高速局域网),上限应为2*MSL,即240秒。

内核中超时时间的计算

​ 参考Linux2.6内核源码中, 发现RTO初始化使用了RFC 1122

#define HZ	100
#define TCP_TIMEOUT_INIT ((unsigned)(3*HZ))	/* RFC 1122 initial RTO value	*/

​ 在static int tcp_v4_init_sock(struct sock *sk)中初始化时就会使用TCP_TIMEOUT_INIT初始化一个连接的RTO

static int tcp_v4_init_sock(struct sock *sk)
{
	struct tcp_sock *tp = tcp_sk(sk);

	skb_queue_head_init(&tp->out_of_order_queue);
	tcp_init_xmit_timers(sk);
	tcp_prequeue_init(tp);

	tp->rto  = TCP_TIMEOUT_INIT;//初始化RTO
	tp->mdev = TCP_TIMEOUT_INIT;
    
	......
}

​ 在超时重传时, tatic void tcp_retransmit_timer(struct sock *sk)对RTO做处理

static void tcp_retransmit_timer(struct sock *sk)
{
    ......
        /**
	 * 如果重传超时,检查当前资源使用情况并决定是否重传。
	 * 如果重传次数达到上限,则需要强制关闭套接字。
	 * 如果仅资源使用达到上限,则不重传。
	 */
	if (tcp_write_timeout(sk))
		goto out;
    
    ......
        
out_reset_timer:
	/* 设置重传超时时间,然后重置重传定时器 */
	tp->rto = min(tp->rto << 1, TCP_RTO_MAX);//2倍扩
	tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
	if (tp->retransmits > sysctl_tcp_retries1)
		__sk_dst_reset(sk);
    
    ......
}
#define TCP_RTO_MAX	((unsigned)(120*HZ))

可以看出RTO初始值为3秒, 最大值为120秒, 每次超时重传2倍增加, 不超过120秒, 并且如果重传次数达到上限就会关闭该连接

滑动窗口

滑动窗口

​ 对每一个发送的数据段, 都要给一个ACK确认应答, 收到ACK后再发送下一个数据段.这样做有一个比较大的缺点, 就是性能较差, 尤其是数据往返的时间较长的时候, 那么我们一次发送多条数据, 以此提高性能

​ 滑动窗口(是缓冲区的一部分,size=min(对方接收缓冲区剩余空间的大小, 拥塞窗口大小)

  • 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值, 比如一个滑动窗口有四个段
  • 发送前四个段的时候, 不需要等待任何 ACK, 直接发送
  • 收到第一个 ACK 后, 滑动窗口向后移动, 继续发送第五个段的数据, 依次类推
  • 操作系统内核为了维护这个滑动窗口, 需要开辟发送缓冲区来记录当前还有哪些数据没有应答; 只有确认应答过的数据, 才能从缓冲区删掉

延迟应答

​ 如果接收数据的主机的接收缓冲区很小, 此时如果立刻返回ACK应答, 这时候返回的窗口也比较小, 这样发送方在后续的传输中就可能会受到限制,因为它只能发送少量的数据, 为了提高传输效率, 接收方可以延迟一段时间再发送ACK, 等待一段时间让上层将接收缓冲区的数据读取, 那么自身的接收能力就提高了, 返回的窗口大小更大, 发送方就可以一次发送更多的数据, 当然也不是所有包都能延迟应答, 一些实时性较高的场景会导致应用层性能下降

流量控制

​ 接收端处理数据的速度是有限的, 如果发送方太快以至于接收方来不及处理的, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应, 因此TCP支持根据接收端的处理能力, 来决定发送端的发送速度, 这个机制就叫做流量控制(Flow Control)

  • 接收端将自己可以接收的缓冲区大小放入TCP首部中的 16位窗口大小字段和附加首部选项 ( 16位可能不够 ) 通知对方自己的接收能力
  • 如果接收端缓冲区满了,就会将窗口置为0, 这时发送方不再发送数据,但是会定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端

拥塞控制

​ TCP 协议中用于防止网络出现过度拥塞的机制。它的目标是确保网络在高负载下依然能够有效传输数据,避免由于拥塞引起的丢包和延迟问题, 因为网络上有很多的计算机, 可能当前的网络状态就已经比较拥堵, 在不清楚当前网络状态下, 贸然发送大量的数据可能会加重网络拥堵程度, 首先是慢启动拥塞窗口指数增长, 拥塞窗口达到阈值后成线性增长, 直到发生大量丢包, 认为网络堵塞, 拥塞窗口阈值将置为当前拥塞窗口大小一半, 然后将拥塞窗口设置1, 重新慢启动

在这里插入图片描述

慢启动

​ 慢启动为发送方的 TCP 增加了另一个窗口:拥塞窗口(congestion window),记为 cwnd

  • 初始时,TCP 的 拥塞窗口 被设置为一个较小的值,通常为 1 或 2 个最大报文段(MSS,Maximum Segment Size)。

  • 每收到一个 确认(ACK),拥塞窗口会 增加 1 个 MSS。

  • 在慢启动阶段,拥塞窗口每经过一个往返时间(RTT),就会指数增长。这种指数增长非常快速,直到达到网络的承载能力或进入下一个阶段。

  • 当TCP开始启动的时候,慢启动阈值等于窗口最大值

  • 当拥塞窗口达到阈值时,进入 拥塞避免阶段

拥塞避免

​ 当慢启动的拥塞窗口超过慢启动阈值的时候,不再按照指数方式增长,而是按照线性方式增长

  • 在拥塞避免阶段,拥塞窗口每经过一个 RTT 就增加一个 MSS(线性增长),而不是像慢启动阶段那样指数增长。
  • 线性增长的目的是平稳地增加数据传输速率,避免网络中出现拥塞
  • 当网络状态稳定且没有发生拥塞时,TCP 会逐步增加发送窗口,充分利用带宽
  • 当拥塞发生时(超时或收到重复确认),拥塞窗口阈值被设置为当前窗口大小的一半(拥塞窗口和接收方通告窗口大小的最小值,但最少为 2个报文段)。此外,如果是超时引起了拥塞,则拥塞窗口被设置为1个报文段(重新开始慢启动)。

快重传

​ 当发送方接收到 三个重复的 ACK,它推测网络中丢失了某些数据包。发送方会立即进行重传,这时会进入快速恢复阶段

​ 结合之前的确认序号, 比如发送方发送了序号1000 - 1099 1100 - 1199 1200 - 1299 1300 - 1399 这四个报文, 如果第一个报文丢失, 因为确认序号表示该序号的以前的报文都收到了, 第一个报文没有收到, 即时后面的报文都收到了, 接收方对于后面几个报文的应答中确认序号依然是1000, 此时发送方收到三个确认序号相同的ACK, 发送方就知道是1000这个报文丢失了, 此时发送方会立即进行重传

快速恢复

​ 快速恢复是在发生丢包情况下, 用来快速恢复数据的发送速率,并避免过度减小拥塞窗口, 通常和快重传搭配,

  • 将 拥塞窗口设置为当前的慢启动阈值,即 cwnd = ssthresh。
  • 将 慢启动阈值(ssthresh)设置为当前的 cwnd / 2,目的是减少发送速率,避免过多的数据继续传输到网络中。
  • 发送方继续发送数据,但 cwnd 不会像慢启动那样从 1 MSS 开始增大,而是通过线性增长恢复发送速率。

保活机制

​ TCP 保活机制是确保 TCP 连接在长时间空闲的情况下不会因为网络故障或对方设备问题而中断的机制。它通过周期性地发送小的数据包来检查连接的状态,确保通信双方都处于活动状态。

​ 通过一个半开放连接发送数据会导致返回一个复位, 但那是在来自正在发送数据的客户端。如果客户已经消失了,使得在服务器上留下一个半开放连接,而服务器又在等待来自客户的数据,则服务器将永远等待下去。保活功能就是试图在服务器端检测到这种半开放的连接

  • 检测死连接:TCP 保活机制主要用于检测长时间没有数据传输的连接是否仍然处于活动状态。如果对方没有响应,发送方可以确定连接已经断开或发生了网络问题。
  • 避免空闲连接超时:一些防火墙和路由器可能会在连接空闲时间较长时自动断开连接。TCP 保活机制可以防止这些设备因空闲超时而丢弃连接

TCP 保活机制通过周期性地发送保活探测包来检查连接是否仍然有效

  1. 空闲连接:在 TCP 连接长时间没有数据传输时,发送方开始启动保活机制。这个空闲时间通常由 TCP 保活探测间隔(TCP_KEEPIDLE) 配置。
  2. 发送保活探测包:如果没有接收到数据包,TCP 会按照一定的间隔周期发送小的 保活探测包(通常是 1 字节的数据包),并等待接收方的响应。
  3. 等待接收方响应:如果接收方仍然存在并且连接正常,它会返回一个 ACK 来确认收到保活探测包, 如果发送方连续发送了多个保活探测包都没能得到响应, 那么发送方会认为该连接已经关闭, 从而关闭连接

参考资料

  • 《TCP/IP详解 卷1: 协议》
  • Linux2.6内核源码
  • RFC - 793(RFC 793: Transmission Control Protocol)
  • RFC - 1122(RFC 1122: Requirements for Internet Hosts - Communication Layers)

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

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

相关文章

C#打印设计器

C# 打印设计器&#xff0c;功能强大却操作简单&#xff0c;小白也能快速上手&#xff01; 主要功能&#xff1a; 支持多种设计元素&#xff1a; 文字、图片、图形、二维码、条形码等&#xff0c;满足您多样化的设计需求。 灵活排版&#xff0c;精准定位&#xff1a; 支持拖拽…

【指令集】Nginx

本文作者&#xff1a; slience_me 【指令集】Nginx 1. 目录结构 Nginx 的基础目录结构通常包括以下几个主要目录&#xff1a; Nginx的目录结构大致如下&#xff08;以Linux系统为例&#xff09;&#xff1a; /etc/nginx/ # Nginx的配置文件目录 ├── ngin…

硬件开发笔记(三十四):AHD转MIPI国产方案详解XS9922B(一):芯片方案介绍

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/145651548 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

Python的那些事第二十一篇:Python Web开发的“秘密武器”Flask

基于 Flask 框架的 Python Web 开发研究 摘要 在 Web 开发的江湖里,Python 是一位武林高手,而 Flask 则是它手中那把小巧却锋利的匕首。本文以 Flask 框架为核心,深入探讨了它在 Python Web 开发中的应用。通过幽默风趣的笔触,结合实例和表格,分析了 Flask 的特性、优势以…

如何从0开始做一款AI产品(下)

上篇文章介绍了如何打造教育AI软硬协同型AI产品&#xff0c;本篇文章主要介绍打造客服AI型产品和打造新零售AI的产品。 打造客服AI的产品 传统的客服时代&#xff0c;客服工作重复性高&#xff0c;技术含量低&#xff0c;呼出效率低&#xff0c;客服水平参差不齐。并且管理难度…

无人机不等同轴旋翼架构设计应用探究

“结果显示&#xff0c;对于不等组合&#xff0c;用户应将较小的螺旋桨置于上游以提高能效&#xff0c;但若追求最大推力&#xff0c;则两个相等的螺旋桨更为理想。” 在近期的研究《不等同轴旋翼性能特性探究》中&#xff0c;Max Miles和Stephen D. Prior博士深入探讨了不同螺…

python包的管理

管理python包 python能跻身最欢迎编程语言前列的一个主要原因是python有着活跃的社区提供丰富的包&#xff0c;诸如numpy&#xff0c;pandas&#xff0c;scikit-learn等等。 python的包都存放PyPI中&#xff0c;PyPI即Python Package Index&#xff0c;是python的软件仓库。所…

探索C语言中判断字符串循环移位关系的实现

在C语言的字符串处理中&#xff0c;判断两个字符串是否为循环移位关系是一个有趣且实用的问题。今天&#xff0c;我们就通过一段具体的代码来深入探讨这个问题的解决方案。 代码实现 代码逐行解析 预处理指令和头文件包含 #define _CRT_SECURE_NO_WARNINGS 用于禁用一些与安全…

【推理llm论文精度】DeepSeek-R1:强化学习驱动LLM推理能力飞跃

最近deepseek R1模型大火&#xff0c;正好复习一下他家的技惊四座的论文https://arxiv.org/pdf/2501.12948 近年来&#xff0c;大型语言模型&#xff08;LLM&#xff09;在推理能力上取得了显著进展&#xff0c;但如何进一步有效提升仍然是研究热点。DeepSeek-AI发布了 DeepS…

硬件学习笔记--42 电磁兼容试验-6 传导差模电流干扰试验介绍

目录 电磁兼容试验-传导差模电流试验 1.试验目的 2.试验方法 3.判定依据及意义 电磁兼容试验-传导差模电流干扰试验 驻留时间是在规定频率下影响量施加的持续时间。被试设备&#xff08;EUT&#xff09;在经受扫频频带的电磁影响量或电磁干扰的情况下&#xff0c;在每个步进…

【Java学习】类和对象

目录 一、选择取块解 二、类变量 三、似复刻变量 四、类变量的指向对象 五、变量的解引用访问 1.new 类变量(参) 2.this(参) 3.类变量/似复刻变量. 六、代码块 七、复制变量的赋值顺序 八、访问限定符 1.private 2.default 九、导类 一、选择取块解 解引用都有可以…

I.MX6ull-I2C

一,I2C总线介绍 I2C(Inter-Integrated Circuit 集成电路)总线是Philips公司在八十年代初推出的一种串行、半双工的总 线&#xff0c;主要用于近距离、低速的芯片之间的通信&#xff1b;I2C总线有两根双向的信号线&#xff0c;一根数据线SDA用于收 发数据&#xff0c;一根时钟线…

从插入排序到希尔排序

从插入排序到希尔排序 插入排序 原理 插入排序是一种简单直观的排序算法&#xff0c;其基本思想是通过将每个元素逐个插入到已排序的部分中&#xff0c;逐步构建一个有序序列。 操作步骤 初始化&#xff1a;将第 1 个元素视为已经有序的部分&#xff08;初始时长度为 1&#xf…

AcWing——3624. 三值字符串

双指针解法 #include<iostream> #include<unordered_map> using namespace std; int main() {int n; cin >> n;while(n--){unordered_map<char, int> tree;string s; cin >> s;int ans 0x7fffffff; for(int i 0, j 0; j < (int)s.size();…

【Vue3源码解析】响应式原理

源码环境搭建 【Vue3源码解析】应用实例创建及页面渲染-CSDN博客 写文章时的Vue 版本&#xff1a; "version": "3.5.13",针对单个包进行开发环境打包、测试。 pnpm run dev reactivityreactive 创建响应式对象 packages/reactivity/src/reactive.ts …

刷题记录(回顾)HOT100 二叉树-10: ​199. 二叉树的右视图

题目&#xff1a;199. 二叉树的右视图 难度&#xff1a;中等 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左 子树 只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左…

书籍推荐:《书法课》林曦

记得樊登老师说过&#xff0c;如果你想了解一个事物&#xff0c;就去读5本相关的书&#xff0c;你会比大部分人都更了解它。这是我读的第4本和“书法”有关的书&#xff0c;作为一个零基础的成年人&#xff0c;林曦这本《书法课》非常值得一读。&#xff08;无论你是否写字&…

一个根据输入内容过滤下拉选的组件

1.element的select自定义过滤不是很灵&#xff0c;使用了input和dropdown 组件 <template><div class"autocomplete-wrapper"><!-- 使用 el-input 组件 --><el-inputv-model"inputValue"input"handleInput"placeholder&q…

5G与物联网的协同发展:打造智能城市的未来

引言 随着科技的不断进步&#xff0c;智能城市的概念已经不再是科幻小说中的幻想&#xff0c;它正在逐步走进我们的生活。而这背后的两大驱动力无疑是 5G和 物联网&#xff08;IoT&#xff09;。5G网络以其高速率、低延迟、大容量的优势&#xff0c;与物联网的强大连接能力相结…

SpringBoot 与 SpringCloud的版本对应详细版

| Greenwich版本 | 兼容Spring Boot 2.1.x | | Hoxtonl版本 | 兼容Spring Boot 2.2.x | 在实际开发过程中&#xff0c;我们需要更详细的版本对应&#xff1a; | Spring Boot | Spring Cloud | | — | — | | 1.5.2.RELEASE | Dalston.RC1 | | 1.5.9.RELEASE | Edgware.RE…