在TCP两端交互过程中,数据和确认都有可能丢失。TCP通过在发送时设置一个定时器来解决这种问题。如果当定时器溢出时还没有收到确认,它就重传该数据。对任何TCP协议实现而言,怎样决定超时间隔和如何确定重传的频率是提高TCP性能的关键。
这节讲解TCP的超时重传机制,TCP控制块tcp_pcb内部的相关字段为rtime、rttest、rtseq、sa、sv、rto、nrtx,太多了,先不要晕!
与超时时间间隔密切相关的是往返时间(RTT)的估计。RTT是某个字节的数据被发出到该字节确认返回的时间间隔。由于路由器和网络流量均会变化,因此RTT可能经常会发生变化,TCP应该跟踪这些变化并相应地改变其超时时间。
在某段时间内发送方可能会连续发送多个数据包,但发送方只能选择一个发送包启动定时器,估计其RTT值,另外,一个报文段被重发和该报文的确认到来之前不应该更新估计器。协议中利用一些优化算法平滑RTT的值,并根据RTT值设置RTO的值,即下一个数据包的重传超时时间。
先来看看超时重传机制是怎样实现的,再来重点介绍与RTT估计密切相关的部分。前面讲过tcp_output从unsent队列上取下第一个数据段,并调用函数tcp_output_segment将数据段发送出去,发送完毕后,tcp_output将该数据段挂接到unacked队列上,至于挂在unacked队列上的什么位置,那是后话。tcp_output_segment负责将数据段发送出去,发送出去后它要做的工作如下面的代码所示:
if(pcb->rtime == -1)
pcb->rtime = 0;
if (pcb->rttest == 0) {
pcb->rttest = tcp_ticks;
pcb->rtseq =
ntohl(seg->tcphdr->seqno);
}
rtime用于重传定时器的计数,当其值为-1时表示计数器未被使能;当值为非0时表示计数器使能,在这种情况下,rtime的值每500ms被内核加1,当rtime超过rto的值时,在unacked队列上的所有数据段将被重传。rto已经提及过多次,就是我们为数据包所设置的超时重传时间。接下来的rttest字段与RTT估计密切相关,当rttest值为0时表示RTT估计未启动,否则若要启动RTT估计,则应在发送数据包出去后,将rttest的值设置为tcp_ticks(全局变量,系统当前滴答数),并用rtseq字段记录要进行RTT估计的数据段的起始数据编号。当接收到对方返回的ACK编号后,就可以根据rttest与rtseq的值计算RTT了,字段sa、sv与rto值的计算密切相关,放在后续讨论。数据段发送就是这么多了,主要是针对发送出去的数据段启动重传定时器。当然如过数据段发送出去的时候,重传定时器是启动的&#