重读一遍《tcp/ip详解》,感觉比第一遍学的时候领悟又深了一些,做点记录。

一、首先是关于tcp超时重传的问题,简单来说,tcp在发送完一份数据包之后会设定一个定时器,当定时器超时之前还没有关于这份报文的ACK到达的话,tcp就会认为这份报文超时,从而进行重传。但是现在的一个主要问题就是,超时定时器如何设定,设定值太大的话,丢失的数据包不能被及时发送,太小的话,本来没有丢失的数据包也被重传,也会影响网络性能。现在我们需要一个算法来确定RTO(retransmission timeout)。

算法1:RTT = αRTT + (1 - α)M

           RTO = βRTT

其中α推荐取值为0.9,β推荐取值为2,M为RTT的测量值,RTT为往返时延估计值

算法2:Err = M - A

           A = A + g·Err

           D = D + h·(|Err| - D)

           RTO = A + 4·D

其中M为RTT测量值,A为估计值

当报文被发送出去之后,超时定时器启动,经过一个RTO之后如果没有相应的ACK到达,则重发报文,然后超时定时器被定为2RTO,之后如果还是没有收到ACK,则超时时延被定为4RTO,之后是8RTO。。。,但是Karn等人在1987年提出,如果一个报文在超时重传之后又收到了ACK,此时不能更新RTT和RTO,因为不知道此ACK是第一个报文的还是第二个报文的。

二、再有就是tcp拥塞避免的问题。

在tcp协议中,有两个算法帮助实现拥塞避免,一个是慢启动算法,另一个是拥塞避免算法。

慢启动算法:在tcp连接开始时,发送方初始化一个大小为一个最大报文段(MSS)的窗口,称为拥塞窗口,在此后的过程中,发送方每收到一个ACK就将拥塞窗口加1,然后将此窗口和滑动窗口的最小值作为发送窗口。

拥塞避免算法:跟慢启动算法类似,此算法也是在收到ACK时更新拥塞窗口的值,所不同的是它并不是在收到一个ACK后将窗口加1,而是加1/cwnd(拥塞窗口)。具体算法是,cwnd(t+1) = cwnd(t) + mss*mss/cwnd(t)。

下面描述下完整的tcp拥塞避免算法:

对于一个tcp链接,初始化cwnd为1个最大报文段长度,ssthresh为65535字节。然后开始执行慢启动,直到cwnd的值大于ssthresh的值,此后执行拥塞避免。期间如果发生重传(超时或者收到重复的ACK),则将ssthresh的值更新,ssthresh = max(min(cwnd,awnd)/2,2*mss),基本是将ssthresh的值减半,然后分情况讨论,如果是超时导致的重传,则将cwnd变为1,重新开始慢启动,如果是重复ACK导致的重传,则将cwnd变为ssthresh的值,继续往下走,如果cwnd大于ssthresh执行拥塞避免,如果小于则执行慢启动。