【Linux】TCP协议【下二】{流量控制/滑动窗口/延迟应答/捎带应答/拥塞控制}

文章目录

1.流量控制--利用"窗口大小"字段协商数据量大小

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

  1. 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 "窗口大小" 字段, 通过ACK端通知发送端;窗口大小字段越大, 说明网络的吞吐量越高;
  2. 接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端;发送端接受到这个窗口之后, 就会减慢自己的发送速度;
  3. 如果接收端缓冲区满了, 就会将窗口置为0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端。

接收端如何把窗口大小告诉发送端呢?

回忆我们的TCP首部中, 有一个16位窗口字段, 就是存放了窗口大小信息;

那么问题来了, 16位数字最大表示65535, 那么TCP窗口最大就是65535字节么?

实际上, TCP首部40字节选项中还包含了一个窗口扩大因子M, 实际窗口大小是 窗口字段的值左移 M 位;(系统内核支持多大也是一个因素)

1. 1第一次的时候,怎么保证发送数据量是合理的

不要理解三次握手只是三次握手,双方也交换了报文!,已经协商了双方的接受能力(16位窗口大小)!

1.2第三次握手ack的时候,可以携带数据!

(为什么?因为前两次握手已经协商了双方的接受能力)。捎带应答:tcp在保证可靠性的同时也在考虑高效率。

为了知道B能不能接收数据:A在一定条件下会发起只有报头的窗口探测;B达到条件后会主动发窗口更新通知。

双方都有通知策略:

验证网络连通性/提升协议容错性:窗口探测有无应答/窗口更新通知有无新数据。【如果长时间对方无应答 一方会主动断开连接 --- 降低资源利用率】

1.3流量控制,属于可靠性还是属于效率?

可靠性为主效率为辅。减少丢包 -- 可靠。减少重传 -- 效率;

2.滑动窗口--利用滑动窗口解决批量数据发送问题

之前的发一个收一个,即确认应答策略, 对每一个发送的数据段, 都要给一个ACK确认应答. 收到ACK后再发送下一个数据段.这样做有一个比较大的缺点, 就是性能较差. 尤其是数据往返的时间较长的时候.

既然这样一发一收的方式性能较低, 那么我们一次发送多条数据, 就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了).

窗口大小指的是无需等待确认应答而可以继续发送数据的最大值. 上图的窗口大小就是4000个字节(四个段).

发送前四个段的时候, 不需要等待任何ACK, 直接发送;收到第一个ACK后, 滑动窗口向后移动, 继续发送第五个段的数据; 依次类推;

操作系统内核为了维护这个滑动窗口, 需要开辟发送缓冲区来记录当前还有哪些数据没有应答; 只有确认应答过的数据, 才能从缓冲区删掉;

窗口越大, 则网络的吞吐率就越高;【吞吐率】单位时间内通过某通信信道(a communication channel)或某个节点成功交付数据的平均速率,通常以每秒比特数(bps, bits per second )为单位。

  • 已经发出去,但是暂时没有收到应答的报文,要被tcp暂时保存起来 【如果丢失要重传】
  • 已经发出去,但是暂时没有收到应答可能会在发送方存在多个,最大是多少?被保存在哪里?要发送的报文本来就在发送缓冲区,无需二次保存,只需对发送缓冲区做一个区域划分。
  1. 滑动窗口在哪:在发送缓冲区,是发送缓冲区的一部分。
  2. 已发送收到确认的部分可被覆盖 -- 上层看起来就是老数据被发送缓冲区删除了。
  3. 已发送未收到确认的不可被覆盖。当这部分有一块数据收到应答了可以划分进前一部分即已发送已收到应答,即窗口右移!即窗口的滑动!这部分能有多大?
  4. 滑动窗口的范围大小,一般是对方的接收窗口的剩余空间大小,即应答报文中窗口大小字段的大小。因为滑动窗口的大小和对方的接收窗口的剩余空间大小相同,那么就可以一次从窗口里拿很多数据发送给对方。
  5. 如何理解区域划分?通过指针/下标来进行区分即可!
  6. 滑动窗口不是对方的接收窗口的剩余空间大小吗,为什么不一次性把滑动窗口里的数据都发给对方,而是图中分成一块一块的,这样减少IO次数还提高效率,为什么不呢?硬件不允许我们一次性将大量数据交给网卡,其次一旦丢包,丢失的是大量数据,重传也要浪费资源。

2.1数据包抵达,ack丢失【问题不大】

假设2001的包的ack丢了,但是4001的包的ack没丢,那么发送方会收到5001的ack得知对方已经接收了5001之前的报文,即确认序号允许部分ack丢失(无影响)。

5001的ack丢了,4001的ack不丢,那么发送方会超时重传,问题不大。

ack全部丢失,全部超时重传,问题不大。

2.2数据包丢了

2001的数据包丢了,其他都收到了,此时的确认序号只会是2001,虽然3001和4001成功抵达,但是由于确认序号的定义,此时的确认序号只会是2001;即滑动窗口不会越过中间的某一个丢失报文。只会线性连续向后更新,不会出现跳跃的情况。

当某一段报文段丢失之后, 发送端会一直收到 1001 这样的ACK, 就像是在提醒发送端 "1001之前的数据我收到了,我需要 1001往后的数据" 一样;

如果发送端主机连续三次收到了同样一个 "1001" 这样的应答, 就会将对应的数据 1001 - 2000 重新发送;

这个时候接收端收到了 1001 之后, 再次返回的ACK就是5001了(因为3001 - 4000)接收端其实之前就已经收到了, 被放到了接收端操作系统内核的接收缓冲区中;这种机制被称为 "高速重发控制"(也叫 "快重传")

2.3已经有了快重传,为什么还要有超时重传?

快重传有条件,只有收到3个同样的ack时才会触发,是提高效率的。超时重传是兜底的后盾,如果报文是倒数第一个第二个,那么就无法连续发三次ack就不会触发快重传。即能用快重传就用,不能用就超时重传。

2.4只会向右移动,移动时大小变化。

上面我们提到,滑动窗口的范围大小,一般是对方的接收窗口的剩余空间大小,即应答报文中窗口大小字段的大小。当对方接收缓冲区取数据较慢,那么接收缓冲区就有可能被打满,此时滑动窗口大小就为0!即滑动窗口大小是动态变化的!可能有以下几种情况:

右指针不动 左指针++

对方不取数据 窗口变小

左指针右指针++ 且窗口变大(不越界)

对方取走很多,接收缓冲区很大

左指针右指针++ 且窗口变小

对方取走一点 接收缓冲区变小

左指针右指针++ 且窗口不变

发多少 取多少 窗口平移

窗口指针位置

int win_start = 确认序号;

int win_end = 确认序号 + min( win大小,有效数据,拥塞窗口)

【窗口大小字段是在双方交流时互相告知的】

流量控制是通过滑动窗口实现的!

对方取数据很快 控制发数据很多

对方取数据很慢 控制发数据慢一点

发多少数据取决于对方的接受能力

2.5再谈

图片来源

窗口滑动时会越界嘛?

tcp采用环状算法!

引入场景:当连续两次连接时 有可能新连接在发收旧报文 如何处理?

双方通信时 会随机生成一个随机序号x 三次握手交流各自的序号 以较小值作为起始序号 然后协商窗口大小 通信时 发送:x+数组下标 接收:确认序号 - x;

3.延迟应答--为了保证效率

一次发送很多数据,发送效率越高,一次能发送很多数据的前提是对方告知我它可以接收很大的数据,这就需要对方有一个很大的接收缓冲区剩余空间即报文的窗口大小字段尽可能大,怎么能够达到这种效果?1. 上层尽快通过read/recv把数据从内核中取走。2. 给上层一些时间。等他一会,让他取走数据,即收到报文不立即应答,延迟应答!

如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小.

假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K;

但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;

在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;

如果接收端稍微等一会【tcp协议层控制】再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M;

一定要记得, 窗口越大, 网络吞吐量就越大, 传输效率就越高. 我们的目标是在保证网络不拥塞的情况下尽量提高传输效率;

那么所有的包都可以延迟应答么?肯定也不是;

数量限制: 每隔N个包就应答一次;

时间限制: 超过最大延迟时间就应答一次;

具体的数量和超时时间,依据操作系统不同也有差异; 一般N取2, 超时时间取200ms;

4.捎带应答

在延迟应答的基础上, 我们发现, 很多情况下, 客户端服务器在应用层也是 "一发一收" 的. 意味着客户端给服务器说了 "How are you", 服务器也会给客户端回一个 "Fine, thank you"; 那么这个时候ACK就可以搭顺风车, 和服务器回应的 "Fine, thank you" 一起回给客户端。

5.TCP小结

为什么TCP这么复杂? 因为要保证可靠性, 同时又尽可能的提高性能.

可靠性:

校验和

序列号(按序到达,去重)

确认应答(核心)

超时重发

连接管理

流量控制

拥塞控制

提高性能:

滑动窗口

快速重传

延迟应答

捎带应答

其他:

定时器(超时重传定时器, 保活定时器, TIME_WAIT定时器等

三次握手

建立连接

协商起始序号

协商双方接收缓冲区大小

基于TCP应用层协议

HTTP

HTTPS

SSH

Telnet

FTP

SMTP

自己写TCP程序时自定义的应用层协议

TCP/UDP对比:TCP是可靠连接, TCP一定就优于UDP吗? TCP和UDP之间的优点和缺点, 不能简单绝对的进行比较。

TCP用于可靠传输的情况, 应用于文件传输, 重要状态更新等场景;

UDP用于对高速传输和实时性要求较高的通信领域, 例如, 早期的QQ, 视频传输等. 另外UDP可以用于广播;

归根结底, TCP和UDP都是程序员的工具, 什么时机用, 具体怎么用, 还是要根据具体的需求场景去判定.

用UDP实现可靠传输(经典面试题)

参考TCP的可靠性机制, 在应用层实现类似的逻辑;

例如:

引入序列号, 保证数据顺序

引入确认应答, 确保对端收到了数据;

引入超时重传, 如果隔一段时间没有应答, 就重发数据;

6.拥塞控制

前面讲的诸多策略都是关系到发送接收双方的,实际上数据从发到收更多的是在网络中的,tcp考虑到网络问题了吗?考虑到了!

引入

虽然TCP有了滑动窗口这个大杀器, 能够高效可靠的发送大量的数据. 但是如果在刚开始阶段就发送大量的数据, 仍然可能引发问题.

因为网络上有很多的计算机, 可能当前的网络状态就已经比较拥堵. 在不清楚当前网络状态下, 贸然发送大量的数据,是很有可能引起雪上加霜的.

TCP引入 慢启动 机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态,再决定按照多大的速度传输数据;

此处引入一个概念程为拥塞窗口(考虑的是动态的网络的接受能力)

发送开始的时候, 定义拥塞窗口大小为1;

每次收到一个ACK应答, 拥塞窗口加1;

每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送的窗口==》滑动窗口大小 = min(窗口大小,拥塞窗口)

像上面这样的拥塞窗口增长速度, 是指数级别的. "慢启动" 只是指初使时慢, 但是增长速度非常快.

为了不增长的那么快, 因此不能使拥塞窗口单纯的加倍.

此处引入一个叫做慢启动的阈值。当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长

【上图没有考虑对方接收能力大小,这个只是在假设对方接受能力很大时,拥塞窗口最大不能怎么样的问题!】

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

在每次超时重发的时候, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回1;

少量的丢包, 仅仅是触发超时重传; 大量的丢包, 就认为网络拥塞;

当TCP通信开始后, 网络吞吐量会逐渐上升; 随着网络发生拥堵, 吞吐量会立刻下降;

拥塞控制, 归根结底是TCP协议想尽可能快的把数据传输给对方, 但是又要避免给网络造成太大压力的折中方案.

TCP拥塞控制这样的过程, 就好像 热恋的感觉

AI问答

TCP拥塞控制是传输控制协议(TCP)中用于避免网络拥塞的重要机制。它通过动态调整发送方的发送速率来确保网络资源的有效利用,避免过多的数据包在网络中积压,从而提高网络通信效率。以下是TCP拥塞控制的详细概述:

一、TCP拥塞控制概述

网络拥塞是指网络中的资源(如带宽、缓存、处理机等)在某段时间内无法满足所有用户的需求,导致网络性能下降。TCP拥塞控制的目标是通过一系列算法来防止过多的数据注入网络,从而避免网络拥塞。

二、TCP拥塞控制的主要算法

TCP拥塞控制主要包括以下几种算法:

慢开始(Slow Start)

目的:用来确定网络的负载能力或拥塞程度。

算法思路:由小到大逐渐增大拥塞窗口(cwnd)的数值。

初始设置:拥塞窗口的初始值一般为最大分段大小(MSS)的两倍,或根据RFC 5681设置为1至4个MSS。

增长方式:在慢开始阶段,每当收到一个确认报文时,拥塞窗口的大小就增加一个MSS,实现指数级增长。

结束条件:当拥塞窗口超过慢启动阈值(ssthresh)时,算法进入拥塞避免阶段。

拥塞避免(Congestion Avoidance)

目的:让拥塞窗口缓慢地增大,避免出现拥塞。

算法思路:在拥塞避免阶段,拥塞窗口按线性规律缓慢增大,即每经过一个往返时间(RTT),拥塞窗口的大小就增加一个MSS。

调整:如果网络出现拥塞(如重传定时器超时),则调整慢启动阈值和拥塞窗口的大小,重新进入慢开始阶段。

快速重传(Fast Retransmit)

目的:避免超时重传带来的长时间等待。

算法思路:当发送方连续收到三个重复确认时,认为有数据包丢失,立即重传丢失的数据包,而不必等待超时定时器到期。

效果:快速重传可以显著提高网络吞吐量,减少数据包的丢失和重传次数。

快恢复(Fast Recovery)

目的:在快速重传后,迅速恢复网络性能。

算法思路:当发送方收到连续三个重复确认时,将慢启动阈值减半,并将拥塞窗口设置为慢启动阈值的大小,然后执行拥塞避免算法,而不是重新进入慢开始阶段。

三、TCP拥塞控制的实现过程

TCP拥塞控制的实现过程涉及发送方和接收方的交互。发送方根据接收方发送的确认报文和窗口更新报文来调整发送速率和拥塞窗口的大小。在数据传输过程中,如果网络出现拥塞,发送方会收到重复确认或超时信号,从而触发相应的拥塞控制算法来调整发送速率和拥塞窗口的大小。

四、总结

TCP拥塞控制是TCP协议中用于避免网络拥塞的重要机制。它通过慢开始、拥塞避免、快速重传和快恢复等算法来动态调整发送方的发送速率和拥塞窗口的大小,从而确保网络资源的有效利用和通信效率的提高。这些算法共同构成了TCP拥塞控制的完整体系,为互联网的稳定运行提供了有力保障。

6.1引入

  1. 上面讲的是发送接收双方为了保证可靠和效率的诸多策略,一旦涉及到网络范畴,需要考虑的就不仅仅是两台机器,而是使用该网络的所有机器。
  2. 发送数据出了问题除了通信双方出问题还有可能是网络出问题,出现少量丢包一般是常规情况,超时重传即可。出现大量丢包时,可能是硬件设备故障此时需要维修机器,可能是数据量太大引起网络阻塞。如果通信双方出现大量数据丢包问题,tcp会根据发送窗口的大量数据未收到ack来判断网络出问题了!此时应该可以确定的是不能重传,因为已经阻塞了,重传只会加重甚至引起网络瘫痪。
  3. 网络出现拥塞时,并不是该网络中所有在通信的机器都会意识到拥塞,只有因网络拥塞无法交流的机器会意识到,拥塞问题越严重,涉及到的机器也就越多。tcp实现了多台主机面对网络拥塞时共识。

6.2拥塞窗口

拥塞窗口(Congestion Window,简称cwnd)是TCP协议中用于拥塞控制的一个重要概念,旨在防止网络因过多的数据包而拥塞。以下是对拥塞窗口的详细解析:

一、定义与功能

定义:拥塞窗口是发送方在接收到对方的ACK确认前允许向网络发送的数据量。它的大小由发送方根据网络的拥塞情况动态调整。

功能:拥塞窗口通过限制发送方在网络中的数据包数量,避免网络拥塞,从而提高网络的整体性能和稳定性。

二、工作原理

初始值:

在TCP连接的初始阶段,拥塞窗口的大小通常被设置为一个较小的值(如一个报文段的大小,大约1KB)。

在RFC2581中,拥塞窗口的初始值被规定为不超过发送方最大报文段(MSS)的两倍,且不能超过两个TCP包。

调整算法:

慢启动(Slow Start):在连接建立后,每收到一个来自接收方的确认(ACK),拥塞窗口的大小就增加一个段值(通常是MSS的大小)。这个过程一直持续到拥塞窗口的大小达到慢启动阈值(ssthresh)或发生网络拥塞。

拥塞避免(Congestion Avoidance):当拥塞窗口的大小超过慢启动阈值时,拥塞窗口的增长速度会放缓,改为每经过一个往返时间(RTT)就将拥塞窗口的大小增加1(而不是加倍)。这样做可以避免网络因数据包激增而拥塞。

快速重传(Fast Retransmit)和快速恢复(Fast Recovery):如果发送方连续收到三个重复的ACK,说明有数据包丢失,此时会触发快速重传机制,并调整慢启动阈值和拥塞窗口的大小,然后进入快速恢复阶段,以避免不必要的慢启动过程。

动态调整:

拥塞窗口的大小会根据网络的拥塞情况动态调整。如果网络拥塞程度增加,拥塞窗口会减小;如果网络拥塞程度降低,拥塞窗口会增大。

三、与接收窗口的关系

接收窗口(rwnd):接收窗口是接收方所能接收的、还没来得及发ACK确认的数据量。它的大小由接收方的缓冲区大小和处理能力决定。

发送窗口:发送窗口的大小由拥塞窗口和接收窗口中的较小值决定,即Min[cwnd, rwnd]。这意味着发送方在发送数据时必须同时考虑网络的拥塞情况和接收方的接收能力。

四、总结

拥塞窗口是TCP协议中用于拥塞控制的关键机制,它通过动态调整发送方在网络中的数据包数量来避免网络拥塞。拥塞窗口的大小由发送方根据网络的拥塞情况通过慢启动、拥塞避免等算法进行动态调整。同时,发送窗口的大小还受到接收窗口的限制,以确保发送方不会向接收方发送超过其接收能力的数据量。

6.3三大窗口

  1. 接收窗口(rwnd) :接收窗口是接收方所能接收的、还没来得及发ACK确认的数据量。它的大小由接收方的缓冲区大小和处理能力决定。
  2. 拥塞窗口(cwnd):拥塞窗口是发送方在接收到对方的ACK确认前允许向网络发送的数据量。它的大小由发送方根据网络的拥塞情况动态调整。主机判断网络健康程度的指标,超过拥塞窗口大小,会引发网络拥塞,否则不会。网络是动态的,拥塞窗口本身肯定不能是静态的!
  3. 滑动窗口(swnd):大小由拥塞窗口和接收窗口中的较小值决定,即Min[cwnd, rwnd]。这意味着发送方在发送数据时必须同时考虑网络的拥塞情况和接收方的接收能力。

6.2应对拥塞

每台识别到拥塞的机器都要参与进来!

网络出现拥塞,发送少量的报文,如果都ok,网络已经趋于健康了,应该尽快恢复正常通信了!前期慢,增长幅度高!

实际机器发送的数据量,会一直指数增长吗??

不会。1. 拥塞窗口有阈值。2. 即便拥塞窗口很大,发送数据时滑动窗口大小取得是rwnd和cwnd的较小值。

慢启动阈值:最近一次发生网络拥塞时,拥塞窗口大小/2。

总结:讲应用层时,用户只关心应用层协议及可,把数据拷贝到tcp发送缓冲区后,之后的一系列的网络通信细节都是OS完成的!

相关推荐
我们的五年几秒前
【Linux课程学习】:进程描述---PCB(Process Control Block)
linux·运维·c++
qdprobot2 分钟前
ESP32桌面天气摆件加文心一言AI大模型对话Mixly图形化编程STEAM创客教育
网络·人工智能·百度·文心一言·arduino
我言秋日胜春朝★1 小时前
【Linux】进程地址空间
linux·运维·服务器
C-cat.1 小时前
Linux|环境变量
linux·运维·服务器
yunfanleo1 小时前
docker run m3e 配置网络,自动重启,GPU等 配置渠道要点
linux·运维·docker
hakesashou1 小时前
Python中常用的函数介绍
java·网络·python
C++忠实粉丝2 小时前
计算机网络socket编程(4)_TCP socket API 详解
网络·数据结构·c++·网络协议·tcp/ip·计算机网络·算法
九州ip动态2 小时前
做网络推广及游戏注册为什么要换IP
网络·tcp/ip·游戏
Estar.Lee2 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
蝶开三月2 小时前
php:使用socket函数创建WebSocket服务
网络·websocket·网络协议·php·socket