Lwip拥塞控制

        什么样的情况出现说明网络出现了拥塞?出现发送数据报文超时收到3个重复的ACK。这两种情况都说明数据报文段有丢失的情况,我们假定由于报文损坏引起的丢失概率是很低的,因此出现报文丢失,就说明源主机和目的主机之间出现了拥塞。

    TCP是一个可靠的协议,在发送数据后会启动一个超时重传定时器,如果超过RTO时间还未收到ACK,就会重传数据。重传会加重网络的负载,会导致更多的丢包和延迟,因此是无节制的重传不是一个好方法,它之后使得网络更加拥塞。

拥塞控制主要有四种方法:

1) 慢启动

2) 拥塞避免

3) 快速重传

4) 快速恢复


慢启动

    最初的TCP在连接建立成功后会向网络中发送大量的数据包,这样很容易导致网络中路由器缓存空间耗尽,从而发生拥塞的情况。慢启动就是新建立的连接,速度是一点一点慢慢的加起来,该算法是通过观察新分组进入网络的速率应该与另一端返回ACK确认的速率相同。

    慢启动为发生方增加了一个窗口:拥塞窗口cwnd(congestion window)。当与另外一个网络的主机建立连接时,cwnd初始化1个报文段(MSS)。

    拥塞窗口是发送方使用的流量控制,发送窗口是接收方使用的流量控制。发送方取拥塞窗口与通过窗口中较小值作为发送上限。

慢启动算法如下:

1)初始化cwnd=1,为一个报文段,表示可以传输一个MSS大小的数据。慢启动门限ssthresh值初始化为65536。

2)每当收到一个ACK,cwnd++

3)每一个RTT,cwnd=2*cwnd,cwnd的值呈指数级的增长。


    下面结合lwip代码看下慢启动是如何实现的。在客户端调用tcp_connect函数发送一个SYN报文执行主动建链时:

pcb->cwnd =  1;  

pcb->ssthresh =  TCP_WND;  

拥塞窗口cwnd初始化为1个报文段,即MSS大小。慢启动门限ssthresh初始化为TCP_WND,此值可以opt.h中更改,一般为4*TCP_MSS大小。

    在服务器端处于listen状态,在tcp_listen_input函数中处理客户端发过来的SYN报文,并设置cwnd和ssthresh值:

npcb->snd_wnd =  SND_WND_SCALE(npcb, tcphdr->wnd );  

npcb->ssthresh =  LWIP_TCP_INITIAL_SSTHRESH(npcb);  

snd_wnd表示发送方的窗口大小,慢启动门限ssthresh的值设置为snd_wnd的大小。

    在客户端收到服务器发过来的SYN+ACK报文后,在tcp_process函数中做如下设置:

pcb->ssthresh =  LWIP_TCP_INITIAL_SSTHRESH(pcb);  

pcb->cwnd =  LWIP_TCP_CALC_INITIAL_CWND(pcb->mss );

慢启动门限ssthresh值设置为对端的发送窗口snd_wnd,拥塞窗口cwnd值设置为4*MSS大小。

    每当收到一个ACKcwnd就会加1Lwip的tcp_receive函数用来处理接收到的ACK报文

/* Update the congestion control variables (cwnd and ssthresh). */  

if (pcb->cwnd <  pcb->ssthresh ) {  /*执行慢启动*/  

if ((tcpwnd_size_t)(pcb->cwnd +  pcb->mss ) > pcb->cwnd ) {  

pcb->cwnd +=  pcb->mss ;    /*拥塞窗口增加一个报文段*/  

}  

LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd ));  

当cwnd < ssthresh时,执行慢启动,cwnd的值增加mss大小,即一个报文段。

拥塞避免

    当拥塞窗口cwnd的值增加到大于等于慢启动门限ssthresh的值,就会进入拥塞避免。拥塞避免的主要思想是cwnd的值不再指数级增长,而是加法增加。

拥塞避免算法如下:

1)当收到一个ACK后,cwnd += 1/cwnd

这样保证了在一个RTT内,cwnd的增加值不会超过1,从而避免了cwnd增加过快,导致网络拥塞。


    Lwip中执行拥塞避免相关的代码如下:

tcpwnd_size_t new_cwnd = (pcb->cwnd +  pcb->mss *  pcb->mss /  pcb->cwnd );  

if (new_cwnd > pcb->cwnd ) {  

pcb->cwnd =  new_cwnd;  

}  

LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd ));

    上面的代码就是处理拥塞避免部分的代码,代码实现部分cwnd值在每次收到一个ACK后,增加了mss*mss/cwnd大小。

慢启动和拥塞避免是在没有发生拥塞时的拥塞控制机制。


快速重传

    TCP协议通信时,发送的数据和ACK确认都有可能丢失。TCP协议在发送时会设置一个超时定时器来解决这种丢失的问题。如果此定时器超时,就会重传数据。

    接收方在收到一个失序的报文时,会给发送方回一个ACK,告诉发送方期待收到的下一个字节。这个ACK一定是一个重复的ACK,接收方在收到这个重复的ACK后,不会立马认为这是由于报文丢失引起的,因为也有可能是由于几个报文段的乱序引起的。

    如果收到3个重复的ACK,就认为是一个报文段丢失了。这样就会重传丢失的报文段,而不需要等待超时定时器的超时,这就是快速重传算法。





  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值