TCP的保活定时器章节目录
1.情景描述
2.保活举例
前言
许多TCP/IP的初学者会很惊奇地发现可以没有任何数据流通过一个空闲的TCP连接。也就是说,如果TCP连接的双方都没有向对方发送数据,则在两个TCP模块之间不交换任何信息。例如,没有可以在其他网络协议中发现的轮询。这意味着我们可以启动一个客户与服务器建立一个连接,然后离去数小时、数天、数个星期或者数月,而连接依然保持。中间路由器可以崩溃和重启,电话线可以被挂断再连通,但是只要两端的主机没有被重启,则连接依然保持建立。
保活并不是TCP规范中的一部分。HostRequirementsRFC提供了3个不使用保活定时器的理由:(1)在出现短暂差错的情况下,这可能会使一个非常好的连接释放掉;(2)它们耗费不必要的带宽;(3)在按分组计费的情况下会在互联网上花掉更多的钱。然而,许多实现提供了保活定时器。
一个说明现在需要使用保活功能的常见例子是当个人计算机用户使用TCP/IP向一个使用Telnet的主机注册时。如果在一天结束时,他们仅仅关闭了电源而没有注销,那么便会留下一个半开放的连接。在图18-16中,我们看到通过一个半开放连接发送数据会导致返回一个复位,但那是在来自正在发送数据的客户端。如果客户已经消失了,使得在服务器上留下一个半开放连接,而服务器又在等待来自客户的数据,则服务器将永远等待下去。保活功能就是试图在服务器端检测到这种半开放的连接。
详现象描述
如果一个给定的连接在两个小时之内没有任何动作,则服务器就向客户发送一个探查报文段(我们将在随后的例子中看到这个探查报文段看起来像什么)。客户主机必须处于以下4个状态之一。
1)客户主机依然正常运行,并从服务器可达。客户的TCP响应正常,而服务器也知道对方是正常工作的。服务器在两小时以后将保活定时器复位。如果在两个小时定时器到时间之前有应用程序的通信量通过此连接,则定时器在交换数据后的未来2小时再复位。
2)客户主机已经崩溃,并且关闭或者正在重新启动。在任何一种情况下,客户的TCP都没有响应。服务器将不能够收到对探查的响应,并在75秒后超时。服务器总共发送10个这样的探查,每个间隔75秒。如果服务器没有收到一个响应,它就认为客户主机已经关闭并终止连接。
3)客户主机崩溃并已经重新启动。这时服务器将收到一个对其保活探查的响应,但是这个响应是一个复位,使得服务器终止这个连接。
4)客户主机正常运行,但是从服务器不可达。这与状态2相同,因为TCP不能够区分状态4与状态2之间的区别,它所能发现的就是没有收到探查的响应。
在第1种情况下,服务器的应用程序没有感觉到保活探查的发生。TCP层负责一切。这个过程对应用程序都是透明的,直至第2、3或4种情况发生。在这三种情况下,服务器应用程序将收到来自它的TCP的差错报告(通常服务器已经向网络发出了读操作请求,然后等待来自客户的数据。如果保活功能返回一个差错,则该差错将作为读操作的返回值返回给服务器)。
在第2种情况下,差错是诸如“连接超时”之类的信息,而在第3种情况则为“连接被对方复位”。第4种情况看起来像是连接超时,也可根据是否收到与连接有关的ICMP差错来返回其他的差错。在下一节中我们将观察这4种情况。
一个被人们不断讨论的关于保活选项的问题就是两个小时的空闲时间是否可以改变。通常他们希望该数值可以小得多,处在分钟的数量级。正如我们在附录E看到的,这个值通常可以改变,但是在该附录所描述的所有系统中,保活间隔时间是系统级的变量,因此改变它会影响到所有使用该功能的用户。
HostRequirementsRFC提到一个实现可提供保活的功能,但是除非应用程序指明要这样,否则就不能使用该功能。而且,保活间隔必须是可配置的,但是其默认值必须不小于两个小时。
保活举例
另一端奔溃
客户在第1、2和3行向服务器发送“Hello,world”并得到回显。第4行是第一个保活探查,发生在两个小时以后(7200秒)。在第6行的TCP报文段能够发送之前,首先观察到的是一个ARP请求和一个ARP应答。第6行的保活探查引出来自另一端的响应(第7行)。两个小时以后,在第7和8行发生了同样的分组交换过程。
如果能够观察到第6和第10行的保活探查中的所有字段,我们就会发现序号字段比下一个将要发送的序号字段小1(在本例中,当下一个为14时,它就是13)。但是因为报文段中没有数据,tcpdump不能打印出序号字段(它仅能够打印出设置了SYN、FIN或RST标志的空数据的序号)。正是接收到这个不正确的序号,才导致服务器的TCP对保活探查进行响应。这个响应告诉客户,服务器下一个期望的序号是14。
接着我们拔掉电缆,并期望两个小时的再一次探查失败。当这下一个探查发生时,注意到从来没有看到电缆上出现TCP报文段,这是因为主机没有响应ARP请求。在放弃之前,我们仍可以观察到客户每隔75秒发送一个探查,一共发送了10次。从交互式脚本可以看到返回给客户进程的差错码被TCP转换为“连接超时”,这正是实际所发生的。
另一端崩溃并重新启动
我们建立了连接,并从客户发送9个字节的数据到服务器(第1~3行)。两个小时之后,客户发送第1个保活探查,其响应是一个来自服务器的复位。客户应用进程打印出“连接被对端复位”的差错,这是有意义的。
另一端不可达
我们与以前一样开始讨论这个例子:第1~3行证实连接是有效的。两个小时之后的第1个保活探查是正常的(第4、5行),但是在两个小时后发生下一个探查之前,我们断开在路由器sun和netb之间的SLIP连接(拓扑结构参见封)。
第6行的保活探查引发一个来自路由器sun的ICMP网络不可达的差错。正如我们在第21.10节描述的那样,对于主机slip上接收的TCP而言,这只是一个软差错。它报告收到了一个ICMP差错,但是差错的接收者并没有终止这个连接。在发送主机最终放弃之前,一共发送了9个保活探查,间隔为75秒。这时返回给应用进程的差错产生了一个不同的报文:“没有到达主机的路由”。