TCP拥塞控制原理

TCP拥塞控制原理:


TCP使用的是端到端的拥塞控制而不是网络辅助的拥塞控制,因为IP层不向端系统提供显示的网络拥塞反馈。

TCP采用的方法是让每一个发送方根据所感知到的网络拥塞的程度,来限制其能向连接发送流量的速率。


这种方法有三个问题:
  <1>一个TCP发送方是如何限制向连接发送流量的速率?
  <2>一个TCP发送方是如何感知它到目的地之间的路径上存在拥塞的呢?
  <3>当发送方感知网络拥塞时,采用什么算法来改变其发送速率的?



对于问题<1>:

  TCP连接的每一端都由一个接收缓存,一个发送缓存和几个变量(LastByteRead,RcvWindow等)组成。TCP拥塞控制机制让连接的每一端都记录一个额外的变量,即拥塞窗口(congestion window)。拥塞窗口表示为congwin,他能限制一个TCP发送方向网络中发送流量的速率。特别是在一个发送方中从未被确认的数据量不会超过congwin与RcvWindow中的最小值,即:LastByteSent-LastByteAcked <= min{congwin, RcvWindow};

上面约束了发送方中未被确认的数量,因此间接地限制了发送方的发送速率。

拥塞窗口(congestion window)指某一源端数据流在一个RTT内可以最多发送的数据包数。发送端根据网络拥塞程度所预设的一个大小值,这个值就是拥塞窗口。


对于问题<2>:

  我们定义一个TCP发送方的“丢包事件”为:要么出现超时,要么收到来自接收方的3个冗余ACK。

当出现过度拥塞时,这条路径上一台(或多台)路由器的缓存会溢出,导致数据报(包含一个TCP报文段)被丢弃。丢弃的数据包会引起发送方的丢失事件(要么超时,要么收到3个冗余ACK),发送方就此认为在源到目的的路径上出现了拥塞指示。


对于问题<3>:

  TCP拥塞控制算法(TCP congestion control algorithm),包含三个部分:1、加性增(additive-increase)、乘性减(multiplicative-decrease)。2、慢启动(slow start)。3、对超时事件做出反应


1、加性增、乘性减(additive-increase multiplicative-decrease,AIMD
  TCP拥塞控制的思想:当出现丢包事件时,让发送方降低其发送速率(通过减小拥塞窗口congwin的大小)。

(因为:通过该相同的拥塞路由器的其他TCP连接也很可能出现丢包事件,所以他们也可能会减小其congwin的值来降低发送速率,因此该整体作用是让所有通过这一拥塞路由器路径的源降低他们向网络发送数据的速率,从而减轻了拥塞路由器的拥塞程度)


但是当出现丢包事件后,TCP发送方应将其拥塞窗口减少多少呢?
  TCP采用一种“乘性减”的方法,即每发生一次丢包事件,就将当前的congwin值减半。但是不能降低到低于1个MSS。


那么当网络无拥塞的时候,即对前面的还没有确认的数据有ACK到达时,他应该怎样来扩大其发送速率?

   增大发送速率的基本原理是:如果没有检测到拥塞,则可能有可用(未使用的)宽带可被该TCP连接使用。这种情况下TCP缓慢地拥塞窗口的长度,谨慎地探测端到端路径上的额外的可用宽带。TCP发送方是这样做的,即每次它接收到一个确认后就把congwin增大一点,其目标是在每个往返时延内congwin增加一个MSS。
总而言之,当TCP发送方感受到端到端路径无拥塞时就加性地增加其发送速率,当察觉到路径拥塞时(通过丢包事件)就乘性地减小其发送速率,因此被称为加性增、乘性减算法


TCP拥塞控制协议的线性增长阶段被称为避免拥塞(congestion avoidance)。congwin值重复地经历一种升降循环,即重复地线性增长,然后又突然降至其当前值的一半(当发生丢包事件时),这种循环是的长寿命TCP连接的congwin变化呈锯齿形状。


             
2、慢启动(slow start,SS):
  当一个TCP连接开始时congwin的值初始设置为1一个MSS,这就使得初始发送速率大约为:MSS/RTT。

  TCP发送方初始阶段不是线性地增加其发送率,而是以指数的速度增加,即每过一个RTT将congwin值翻倍。TCP发送方继续以指数速度增加其发送速率,知道发生一个丢包事件为止,此时congwin将被降为一半,然后再线性地增长,这个被称为慢启动(slow start,SS)的初始化阶段。在慢启动阶段,每过一个RTT,congwin的值将有效地增加一倍。


3、对超时事件做出反应:

  TCP拥塞控制对因超时而检测到的丢包事件做出的反应与因受到3个冗余ACK而检测到的丢包事件做出的反应是不同的。收到3个冗余ACK后,TCP将拥塞窗口减小一半,然后先行地增长。但是超时事件发生时TCP发送方进入一个慢启动阶段,即他将拥塞窗口设置为1MSS,然后窗口以指数速度增长。拥塞窗口持续以指数速率增长,直到congwin达到超时事件前窗口值得一半为止。



以下是TCP Reno算法的简单实现代码: ``` #include <stdio.h> #include <stdlib.h> #define MAX_PACKETS 1000 // 最大数据包数量 #define MSS 512 // 最大段大小 #define RTT 200 // 往返时间 #define ALPHA 0.125 // 慢启动下降因子 #define BETA 0.25 // 拥塞避免下降因子 #define THRESHOLD 16 // 拥塞阈值 // TCP Reno算法状态 typedef enum { SLOW_START, CONGESTION_AVOIDANCE, FAST_RECOVERY } TCP_Reno_State; // 数据包结构体 typedef struct { int seq_num; // 序列号 int size; // 数据包大小 } Packet; // 计算超时时间 int timeout() { return 2 * RTT; } // 慢启动算法 int slow_start(int cwnd, int ssthresh) { cwnd += MSS; if (cwnd >= ssthresh) { return CONGESTION_AVOIDANCE; } return SLOW_START; } // 拥塞避免算法 int congestion_avoidance(int cwnd, int ssthresh) { cwnd += MSS * (MSS / cwnd); if (cwnd >= ssthresh) { return CONGESTION_AVOIDANCE; } return SLOW_START; } // 快速恢复算法 int fast_recovery(int cwnd, int ssthresh) { cwnd = ssthresh; return CONGESTION_AVOIDANCE; } // TCP Reno算法 int tcp_reno(Packet packets[], int num_packets) { int cwnd = MSS; int ssthresh = THRESHOLD * MSS; int state = SLOW_START; int acked = 0; int dup_ack_count = 0; int i; for (i = 0; i < num_packets; i++) { // 接收到确认号 if (packets[i].seq_num <= acked) { continue; } acked = packets[i].seq_num; // 慢启动状态下 if (state == SLOW_START) { state = slow_start(cwnd, ssthresh); } // 拥塞避免状态下 else if (state == CONGESTION_AVOIDANCE) { state = congestion_avoidance(cwnd, ssthresh); } // 快速恢复状态下 else if (state == FAST_RECOVERY) { cwnd += MSS; state = CONGESTION_AVOIDANCE; } // 重传数据包 if (dup_ack_count >= 3) { ssthresh = cwnd / 2; cwnd = ssthresh + 3 * MSS; state = FAST_RECOVERY; dup_ack_count = 0; continue; } // 发送数据包 while (cwnd >= packets[i].size) { cwnd -= packets[i].size; } // 接收到重复确认号 if (packets[i].seq_num == acked) { dup_ack_count++; continue; } // 更新拥塞窗口大小 if (state == SLOW_START) { cwnd += MSS; } else if (state == CONGESTION_AVOIDANCE) { cwnd += MSS * (MSS / cwnd); } } return 0; } // 主函数 int main() { Packet packets[MAX_PACKETS]; int num_packets; int i; for (i = 0; i < num_packets; i++) { packets[i].seq_num = i; packets[i].size = MSS; } tcp_reno(packets, num_packets); return 0; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值