传输层协议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;//初始化RTOtp->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)

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

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

相关文章

vscode使用常见问题处理合集

目录 一、使用vite创建的vue3项目&#xff0c;script和style首行代码不会缩进,且格式化属性字段等会换行问题 首行缩进情况如下&#xff1a; 属性、参数格式化换行情况如下&#xff1a; 解决方式&#xff1a; 一、使用vite创建的vue3项目&#xff0c;script和style首行代码不…

【C语言】程序环境与预处理

目录 程序的翻译环境和执行环境 粗谈编译链接 翻译环境 编译的几个阶段及链接 运行环境 预处理详解 预定义符号 #define #define 定义标识符 #define 定义宏 #define 替换规则 #和## 带副作用的宏参数 宏和函数的对比 命名约定 #undef 命令行定义 条件编译 …

类与对象C++详解(中)-----构造函数与析构函数

1.构造函数 构造函数是一个特殊的成员函数&#xff0c;函数名和类名相同&#xff0c;构造函数的作用是初始化&#xff0c;以下是构造函数的一些特点&#xff1a; 1. 函数名与类名相同。 2. ⽆返回值。(返回值啥都不需要给&#xff0c;也不需要写void&#xff0c;不要纠结&#…

计算机网络(1)基础篇

目录 1.TCP/IP 网络模型 2.键入网址--->网页显示 2.1 生成HTTP数据包 2.2 DNS服务器进行域名与IP转换 2.3 建立TCP连接 2.4 生成IP头部和MAC头部 2.5 网卡、交换机、路由器 3 Linux系统收发网络包 1.TCP/IP 网络模型 首先&#xff0c;为什么要有 TCP/IP 网络模型&a…

【JavaEE进阶】验证码案例

目 &#x1f332;实现说明 &#x1f384;Hutool介绍 &#x1f333;准备工作 &#x1f334;约定前后端交互接口 &#x1f6a9;接口定义 &#x1f6a9;实现服务器后端代码 &#x1f6a9;前端代码 &#x1f6a9;整体测试 &#x1f332;实现说明 随着安全性的要求越来越⾼…

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

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

机器学习·最近邻方法(k-NN)

前言 上一篇简单介绍了决策树&#xff0c;而本篇讲解与决策树相近的 最近邻方法k-NN。 机器学习决策树-CSDN博客 一、算法原理对比 特性决策树最近邻方法&#xff08;k-NN&#xff09;核心思想通过特征分割构建树结构&#xff0c;递归划分数据基于距离度量&#xff0c;用最近…

Deesek:新一代数据处理与分析框架实战指南

Deesek&#xff1a;新一代数据处理与分析框架实战指南 引言 在大数据时代&#xff0c;高效处理和分析海量数据是企业和开发者面临的核心挑战。传统工具如Pandas、Spark等虽功能强大&#xff0c;但在实时性、易用性或性能上仍有提升空间。Deesek&#xff08;假设名称&#xff…

【Vue】打包vue3+vite项目发布到github page的完整过程

文章目录 第一步&#xff1a;打包第二步&#xff1a;github仓库设置第三步&#xff1a;安装插件gh-pages第四步&#xff1a;两个配置第五步&#xff1a;上传github其他问题1. 路由2.待补充 参考文章&#xff1a; 环境&#xff1a; vue3vite windows11&#xff08;使用终端即可&…

JVM内存模型详解

文章目录 1. 程序计数器&#xff08;Program Counter Register&#xff09;2. Java虚拟机栈&#xff08;Java Virtual Machine Stacks&#xff09;3. 本地方法栈&#xff08;Native Method Stacks&#xff09;4. Java堆&#xff08;Java Heap&#xff09;5. 方法区&#xff08;…

KubeSphere 和 K8s 高可用集群离线部署全攻略

本文首发&#xff1a;运维有术&#xff0c;作者术哥。 今天&#xff0c;我们将一起探索如何在离线环境中部署 K8s v1.30.6 和 KubeSphere v4.1.2 高可用集群。对于离线环境的镜像仓库管理&#xff0c;官方推荐使用 Harbor 作为镜像仓库管理工具&#xff0c;它为企业级用户提供…

代码随想录-训练营-day30

今天我们要进入动态规划的背包问题&#xff0c;背包问题也是一类经典问题了。总的来说可以分为&#xff1a; 今天让我们先来复习0-1背包的题目&#xff0c;这也是所有背包问题的基础。所谓的0-1背包问题一般来说就是给一个背包带有最大容量&#xff0c;然后给一个物体对应的需要…

百问网(100ask)提供的烧写工具的原理和详解;将自己编译生成的u-boot镜像文件烧写到eMMC中

百问网(100ask)提供的烧写工具的原理 具体的实现原理见链接 http://wiki.100ask.org/100ask_imx6ull_tool 为了防止上面这个链接失效&#xff0c;我还对上面这个链接指向的页面保存成了mhtml文件&#xff0c;这个mhtml文件的百度网盘下载链接&#xff1a; https://pan.baidu.c…

【旋转框目标检测】基于YOLO11/v8深度学习的遥感视角船只智能检测系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

侯捷 C++ 课程学习笔记:C++ 面向对象开发的艺术

在侯捷老师的 C 系列课程中&#xff0c;《C 面向对象开发》这门课程让我对面向对象编程有了更深入的理解。面向对象编程&#xff08;OOP&#xff09;是现代软件开发中最重要的编程范式之一&#xff0c;而 C 作为支持 OOP 的语言&#xff0c;提供了强大的工具和特性。侯捷老师通…

神经网络常见激活函数 12-Swish函数

Swish 函数导函数 Swish函数 S w i s h ( x ) x ⋅ σ ( β x ) x 1 e − β x \begin{aligned} \rm Swish(x) & x \cdot \sigma(\beta x) \\ & \frac{x}{1 e^{-\beta x}} \end{aligned} Swish(x)​x⋅σ(βx)1e−βxx​​ Swish函数导数 d d x S w i s h ( x…

CF 137B.Permutation(Java 实现)

题目分析 输入n个样本&#xff0c;将样本调整为从1到n的包含&#xff0c;需要多少此更改 思路分析 由于样本量本身就是n&#xff0c;无论怎么给数据要么是重复要么不在1到n的范围&#xff0c;只需要遍历1到n判断数据组中有没有i值即可。 代码 import java.util.*;public clas…

web第三次作业

弹窗案例 1.首页代码 <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>综合案例</title><st…

go语言简单快速的按顺序遍历kv结构(map)

文章目录 需求描述用map实现按照map的key排序用二维切片实现用结构体实现 需求描述 在go语言中&#xff0c;如果需要对map遍历&#xff0c;每次输出的顺序是不固定的&#xff0c;可以考虑存储为二维切片或结构体。 假设现在需要在页面的下拉菜单中展示一些基础的选项&#xff…

Unity 命令行设置运行在指定的显卡上

设置运行在指定的显卡上 -force-device-index