前言: 网络编程是服务器开发者必不可少的知识储备,在开发过程中总会出现TCP连接的状态问题,所以有必要花时间取好好讨论一番。 一、TCP连接的建立 它的建立必定是经过“三次握手”的流程,那三次握手到底是什么?为什么它如此的重要呢,也是面试官时常喜欢考察的知识点。以下我画个流程图来详解。 上面的流程图包括了TCP 的建立与关闭,也就是常见的“三次握手”与“四次挥手”的流程。 “三次握手”(图中的报文段1~报文段3): 图中的ernest-laptop是客户端,Kongming20是服务端。一般是客户端主动发起连接,服务端被动连接,当ernest-laptop发起连接时发送一条同步报文段1,序号值为535734930(SYN),Kongming20接收到后,也发送一条同步报文段2,序号值2159701207(SYN),表示同意与ernest-laptop建立连接,同时也发送了一个确认值为535734931的ACK,这个ACK是报文段1的序号值+1,序号值是用来标识TCP数据流的每一字节,这里的同步报文段比较特殊,没有携带应用层的数据,但也占有一位的序号值。最后ernest-laptop接收到同步报文段2后,发出了确认值为同步报文段2的序号值+1的ACK,也就完成了三次握手的流程。同步报文段1和同步报文段2的序号值其实是随机值,但ACK的确认值是上一个报文段的序号值+1. 二、TCP连接的关闭 TCP连接的关闭也就是所说的”四次挥手“流程。 “四次挥手”(图纸的报文段4~报文段7) 后面4个TCP报文段是关闭连接的过程。第4个TCP报文段包含FIN标志,因此它是一个结束报文段,即ernest-laptop要求关闭连接。结束报文段和同步报文段一样,也要占用一个序号值。Kongming20用TCP报文段5来确认该结束报文段。紧接着Kongming20发送自己的结束报文段6,ernest-laptop则用TCP报文段7给予确认。实际上,仅用于确认目的的确认报文段5是可以省略的,因为结束报文段6也携带了该确认信息。确认报文段5是否出现在连接断开的过程中,取决于TCP的延迟确认特性。延迟确认将在后面讨论。 在连接的关闭过程中,因为ernest-laptop先发送结束报文段(telnet客户端程序主动退出),故称ernest-laptop执行主动关闭,而称Kongming20执行被动关闭。 三、需要注意的一些状态: 半关闭状态: TCP连接是全双工的,也就是说它允许双方都能发送数据和接收数据。图中的报文段4~报文段7也说明了,双方关闭连接都需要发送一个结束报文段和响应对方的结束报文段,这样就有可能在发送过程中出现各种问题,先讨论其中一种情况:半关闭状态。 半关闭状态:通俗的讲就是一端发送了结束报文段后,就表示本段已结束了数据的发送,但还能接收数据,至到接收到对端的结束报文段,这就是半关闭状态。如图解释: 请注意,在图中,服务器和客户端应用程序判断对方是否已经关闭连接的方法是:read系统调用返回0(收到结束报文段)。当然,Linux还提供其他检测连接是否被对方关闭的方法,这将在后续讨论。 超时连接 前面我们讨论的是很快建立连接的情况。如果客户端访问一个距离它很远的服务器,或者由于网络繁忙,导致服务器对于客户端发送出的同步报文段没有应答,此时客户端程序将产生什么样的行为呢﹖显然,对于提供可靠服务的TCP来说,它必然是先进行重连(可能执行多次),如果重连仍然无效,则通知应用程序连接超时。 这次抓包我们保留了tepdump输出的时间戳(不使用其-t选项),以便推理Linux 的超时重连策略。 我们一共抓取到6个TCP报文段,它们都是同步报文段,并且具有相同的序号值,这说明后面5个同步报文段都是超时重连报文段。观察这些TCP报文段被发送的时间间隔,它们分别为1 s、2s、4 s、8s和16s (由于定时器精度的问题,这些时间间隔都有一定偏差),可以推断最后一个TCP报文段的超时时间是32s (63 s-16 s-8 s-4 s-2 s-1 s)。因此,TCP模块一共执行了5次重连操作,这是由/proclsys/net/ipv4/tcp_syn_retries内核变量所定义的。每次重连的超时时间都增加一倍。在5次重连均失败的情况下,TCP模块放弃连接并通知应用程序。 在应用程序中,我们可以修改连接超时时间,具体方法将在本书后续章节中进行介绍。 四、TCP状态转移
|