3.9 TCP超时重传
在3.6节~3.8节中,我们讲述了TCP在正常网络情况下的数据流。从本节开始,我们讨论异常网络状况下(开始出现超时或丢包),TCP如何控制数据传输以保证其承诺的可靠服务。
TCP服务必须能够重传超时时间内未收到确认的TCP报文段。为此,TCP模块为每个TCP报文段都维护一个重传定时器,该定时器在TCP报文段第一次被发送时启动。如果超时时间内未收到接收方的应答,TCP模块将重传TCP报文段并重置定时器。至于下次重传的超时时间如何选择,以及最多执行多少次重传,就是TCP的重传策略。我们通过实例来研究Linux下TCP的超时重传策略。
在ernest-laptop上启动iperf服务器程序,然后从Kongming20上执行telnet命令登录该服务器程序。接下来,从telnet客户端发送一些数据(此处是“1234”)给服务器,然后断开服务器的网线并再次从客户端发送一些数据给服务器(此处是“12”)。同时,用tcpdump抓取这一过程中客户端和服务器交换的TCP报文段。具体操作过程如下:
$ sudo tcpdump -n -i eth0 port 5001
$ iperf –s #在ernest-laptop上执行
$ telnet 192.168.1.108 5001 #在Kongming20上执行
Trying 192.168.1.108...
Connected to 192.168.1.108.
Escape character is '^]'.
1234 #发送完之后断开服务器网线
12
Connection closed by foreign host
iperf是一个测量网络状况的工具,-s选项表示将其作为服务器运行。iperf默认监听5001端口,并丢弃该端口上接收到的所有数据,相当于一个discard服务器。上述操作过程的部分tcpdump输出如代码清单3-7所示。
TCP报文段1~3是三次握手建立连接的过程,TCP报文段4~5是客户端发送数据“1234”(应用程序数据长度为6,包括回车、换行两个字符,后同)及服务器确认的过程。TCP报文段6是客户端第一次发送数据“12”的过程。因为服务器的网线被断开,所以客户端无法收到TCP报文段6的确认报文段。此后,客户端对TCP报文段6执行了5次重传,它们是TCP报文段7~11,这可以从每个TCP报文段的序号得知。此后,数据包12~23都是ARP模块的输出内容,即Kongming20查询ernest-laptop的MAC地址。
我们保留了tcpdump输出的时间戳,以便推理TCP的超时重传策略。观察TCP报文段6~11被发送的时间间隔,它们分别为0.2?s、0.4?s、0.8?s、1.6?s和3.2?s。由此可见,TCP一共执行5次重传,每次重传超时时间都增加一倍(因此,和TCP超时重连的策略相似)。在5次重传均失败的情况下,底层的IP和ARP开始接管,直到telnet客户端放弃连接为止。
Linux有两个重要的内核参数与TCP超时重传相关:/proc/sys/net/ipv4/tcp_retries1和/proc/sys/net/ipv4/tcp_retries2。前者指定在底层IP接管之前TCP最少执行的重传次数,默认值是3。后者指定连接放弃前TCP最多可以执行的重传次数,默认值是15(一般对应13~30?min)。在我们的实例中,TCP超时重传发生了5次,连接坚持的时间是15?min(可以用date命令来测量)。
虽然超时会导致TCP报文段重传,但TCP报文段的重传可以发生在超时之前,即快速重传,这将在下一节中讨论。