拥塞窗口

      之前学习了滑动窗口,滑动窗口用来根据接收方的能接收数据的缓存大小来对发送方进行流量控制,从而减少网路负担,保证网络的正常运行。但是,在发送端和接收端之间,可能会存在很多中间设备,包括路由器、网关等,这些设备也具有一定的承载数据的上限,也会引起网络拥塞,造成数据的丢失,造成接收端接受数据的失序。为了解决这个问题,引入了拥塞窗口,即在发送端设置一个窗口结构,根据网络的拥塞情况,动态调整该窗口大小,发送端只能发送大小小于滑动窗口和拥塞窗口的数据,在发送端设置的这个窗口就是拥塞窗口。

一、超时重传

      我们知道TCP提供的是面向连接的可靠数据传输。面向连接就是在交换数据前,在收发两端要建立连接。可靠主要体现在对于网络中出现的丢包、包乱序等情况,TCP发送端会根据接收端返回的情况,选择重传这些数据。在TCP中,主要通过两种方式来检测丢包或乱序的出现,第一种是发送端设置超时时间,第二种是接收端发送重复ACK包。

      设置超时时间是指,TCP发送一个报文段时,设置该报文段的超时时间,如果接收端接收到报文段,会给发送端发送一个ACK确认报文,如果发送端在超时时间前未收到对应的ACK报文,发送端则会选择重发丢失的报文,直到发送端收到非重传数据为止。设置超时时间的核心问题是如何确定RTO(Retransmission Time Out, 重传超时时间),有很多关于这个问题的研究和成果。RTO是动态的,会根据网路拥塞情况动态变化。最核心的是,基本上所有的方法都是通过连接的RTT(Round Trip Time, 往返时间)确定RTO。早期的方法是通过每次得到的RTT样本值重新计算新的TRTO值。公式如下。其中SRTT为每次的迭代更新的RTT,RTT为样本RTT测量值。ubound、lbound、β为常量。

image

早期的经

典方法没有考虑到RTT的变化情况,RTT变化情况更能反映当前的拥塞情况,所以Jacobson提出了标准方法。具体公式这里不想讨论。 同时对于我们如何获取样本RTT,也有一些值得探讨的问题。我们一般是通过在发送的报文中设置某些标识,在接收端收到并返回ACK时也会带上这些标识,我们就可测量这段时间为RTT。但是如果在测量RTT时发生超时重传,如果第一个包发生超时,就会重传,接着收到了一个ACK确认报文,但这个确认是对那一次发送的确认呢?可能第一次发送的报文,由于网络拥堵,接收端只是延时收到了,但触发了超时时间,所以这个ACK有可能就是对第一个报文的确认,这就产生了二义性。也就产生了Karn算法。Karn算法包含两个部分,一是发生超时重传时,接受到重传数据的确认信息时不能更新RTT估计值,这样就忽略了二义性的问题。二是采用一个退避指数,每当重传的报文计时器超时时,就让退避指数加倍,即让下一次重发时间加倍,直到接受到非重传数据。

     下面来看基于接收端发给发送端的报文,判断网络的拥塞,是否出现丢包或包乱序的问题。一般情况是,当接收端发现数据丢失或数据乱序时,接收端选择发送重复ACK确认报文,向发送端报告数据丢失或乱序。一般来说,小于三个ACK重复报文代表数据乱序,大于等于三个重复ACK代表数据丢失。当发送端观察到这种情况后,不管超时计时器是否超时,都会选择重发丢失或乱序的数据。

二、慢启动和拥塞控制

       前面了解了超时重发后,我们开始讨论慢启动和拥塞控制。慢启动顾名思义,是为了进行流量控制,发送端控制发送数据的大小的动作。初始时,发送端发送一个报文段,等收到接收端对该报文段的确认ACK后,发送端就可以发送2个报文段,当收到对这两个报文段的确认ACK后,发送端就可以发送4个报文段,一直按照指数增长下去。这种TCP中使用的发送数据的方式为慢启动(Slow Start)。一般在TCP中,慢启动和拥塞控制同时使用。

     下面介绍拥塞控制,拥塞控制也就是在发送端设置一个窗口结构,窗口大小为cwnd,其根据网络的拥塞情况动态变化,也就是根据连接的超时重发情况动态变化。发送端只能发送小于或等于拥塞窗口和滑动窗口大小的数据。初始时cwnd为1,ssthreshold(Start Slow Threshold)为65535。当cwnd <= ssthreshold时,执行慢启动;当cwnd > ssthreshold后,执行拥塞控制。慢启动前面说了可以传输的数据量以指数形式增长。拥塞控制是cwnd线性增长,即要么以1/cwnd,要么以1增长。

     1.当出现因超时引起的重传时,执行:

1.ssthreshold = cwnd / 2

2.cwnd = 1

3.进入慢启动

image

2.当出现发送端接收到三个重复的ACK后发生的重传,执行:

1.cwnd = cwnd / 2

2.ssthreshold = cwnd

3.进入快速恢复算法

 

 

image

快速恢复算法:

1.前面已经更新了cwnd和ssthreshold

2.随后设置cwnd = cwnd + 3 * MSS

3.重传数据

4.再每收到一个重复ACK,cwnd = cwnd + 1

5.直到没收到重复ACK,设置cwnd = ssthreshold

转载于:https://www.cnblogs.com/glsy/p/8605848.html

### 拥塞窗口在TCP消息传输中的定义和功能 #### 定义 拥塞窗口(Congestion Window, cwnd)是 TCP 协议中用于控制发送方数据传输速率的一种机制。它反映了当前网络的可用带宽状况,旨在防止因发送过多数据而导致网络拥塞拥塞窗口的大小动态调整,基于慢启动、拥塞避免、快速重传和快速恢复等算法[^1]。 #### 功能 拥塞窗口的主要功能包括以下几个方面: 1. **动态调整发送速率** 拥塞窗口通过限制每次可以发送的数据量来适应网络状况的变化。当网络条件良好时,拥塞窗口会逐渐增大,允许发送更多数据;而当检测到网络拥塞(如丢包)时,拥塞窗口会迅速减小以缓解压力[^5]。 2. **防止网络拥塞** 通过设置合理的拥塞窗口大小,TCP 能够避免向网络注入过多数据,从而降低网络过载的风险。初始阶段,拥塞窗口通常较小,并以指数级增长的方式进入慢启动阶段,直到达到一个阈值(ssthresh),随后切换为线性增长的拥塞避免阶段[^4]。 3. **结合接收窗口实现流量控制** 拥塞窗口与接收窗口(Receiver Window, rwnd)共同决定了发送方的实际发送窗口大小。发送窗口的大小由两者中的较小值决定,确保既不会超过网络承载能力,也不会超出接收方的处理能力[^2]。 4. **支持快速恢复机制** 在检测到丢包后,TCP 会将拥塞窗口减半并重新设定阈值(ssthresh)。如果后续接收到冗余确认(Duplicate ACKs),则表明丢失的分组可能已被成功重传,此时可以通过快速恢复算法逐步增加拥塞窗口大小,而非直接回到慢启动阶段。 #### 示例代码:拥塞窗口模拟 以下是一个简单的 Python 实现,展示如何模拟 TCP 的拥塞窗口调整逻辑。 ```python class CongestionControl: def __init__(self): self.cwnd = 1 # 初始拥塞窗口大小为1 MSS self.ssthresh = 8 # 初始阈值为8 MSS def slow_start(self): """慢启动阶段""" self.cwnd *= 2 # 拥塞窗口呈指数增长 if self.cwnd >= self.ssthresh: self.congestion_avoidance() # 达到阈值后进入拥塞避免阶段 def congestion_avoidance(self): """拥塞避免阶段""" self.cwnd += 1 # 拥塞窗口线性增长 def on_packet_loss(self): """处理丢包事件""" self.ssthresh = self.cwnd / 2 # 阈值减半 self.cwnd = self.ssthresh # 拥塞窗口减半 # 模拟拥塞窗口变化 cc = CongestionControl() for i in range(10): print(f"Round {i + 1}: cwnd = {cc.cwnd}") cc.slow_start() print("Packet loss detected!") cc.on_packet_loss() print(f"After packet loss: cwnd = {cc.cwnd}, ssthresh = {cc.ssthresh}") ``` #### 结论 拥塞窗口是 TCP 协议中关键的流量控制机制之一,通过动态调整其大小,TCP 能够有效应对网络状况的变化,确保数据传输的高效性和稳定性。同时,它与接收窗口协同工作,进一步优化了网络资源的利用效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值