linux tcp中time_wait
http://www.cnblogs.com/my_life/articles/3460873.html
http://blog.csdn.net/sunnydogzhou/article/details/6572071
http://blog.csdn.net/feiyinzilgd/article/details/5894446
刚刚开始看TCP socket的4次握手终止流程图的时候,对于最后的TIME_WAIT状态不是很理解.现在在回过头来研究,发现TIME_WAIT状态是一个很微妙状态.之所以设计TIME_WAIT状态的原因有2个原因:
- 使得TCP的全双工连接能够可靠的终止.
- 使得连接终止后网络上任然残余的发送给该连接的数据被丢弃而不至于被新连接接收.
在具体详解这两个原因之前,我们需要理解MSL(maxinum segment lifetime)这个概念.
每一个TCP 都必须有一个MSL值.这个值一般是2分钟,但也不是固定的,不同的系统不一样.无论是否出错或者连接被断开,总之,一个数据包在网路上能停留的最大时间是MSL.也就是说MSL是数据包的生命周期时间.超过这个时间,该数据包将会被丢弃而不被发送.而TIME_WAIT状态持续的时间是MSL的两倍,也就是2MSL时间.
- TCP的全双工连接能够被可靠终止
TCP的可靠终止需要经过4次握手终止.如上图所示:首先,client 主动close,导致FIN发送给server,server接收到FIN后,给client回复一个ACK,之后,server会关闭和client的连接,即向client发送一个FIN,client接收到FIN之后,会发送一个ACK给server.此时client就进入TIME_WAIT状态.如果server没有收到ACK,server会重新发送一个FIN信息给client,client会重发ACK,server然后继续等待client发送一个ACK.这样保证了双方的可靠终止.2端都知道对方已经终止了.那么,在这个TIME_WAIT时间中,可以重发ACK,如果client没有收到FIN信息,则TCP会向server发送一个RST信息,这个信息会被server解释成error.
- 连接终止后网络上任然残留的发送到该连接的数据被丢弃而不至于被新连接接收.
举个例子:
假设在10.12.24.48 port:21和206.8.16.32 port:23(不必关心哪一端是server哪一端是client)之间建立了一个TCP连接A.然后此链接A被close掉了.然后此时又在10.12.24.48 port:21和206.8.16.32 port:23(不必关心哪一端是server哪一端是client)之间建立了一个新的TCP连接B.很可能A和B连接是有不同的应用程序建立的.那么,当我们close掉A之后,网络上很有可能还有属于A连接两端的数据m正在网路上被传送.而此时A被close掉了,重新建立了B连接,由于A和B连接的地址和端口都是一样的.这样,m数据就会被最终发送到B连接的两端.这样就造成了混乱,B接收到了原本数据A的数据.处于TIME_WAIT状态的连接会禁止新的同样的连接(如A,B)连接被建立.除非等到TIME_WAIT状态结束,也就是2MSL时间之后.其中,一个MSL时间是为了网络上的正在被发送到该链接的数据被丢弃,另一个MSL使得应答信息被丢弃.这样,2MSL之后,保证重新建立的所得到的数据绝对不会是发往就连接的数据.
=============================================
1 TCP关闭时的四次握手
Tcp连接在关闭的的时候,执行的是一个四次握手的过程,下图是客户端发起的关闭时客户端和服务器的状态转换图
具体过程如下:
1、 客户端发送FIN报文段,进入FIN_WAIT_1状态。
2、 服务器端收到FIN报文段,发送ACK表示确认,进入CLOSE_WAIT状态。
3、 客户端收到FIN的确认报文段,进入FIN_WAIT_2状态。
4、 服务器端发送FIN报文端,进入LAST_ACK状态。
5、 客户端收到FIN报文端,发送FIN的ACK,同时进入TIME_WAIT状态,启动TIME_WAIT定时器,超时时间设为2MSL。
6、 服务器端收到FIN的ACK,进入CLOSED状态。
7、 客户端在2MSL时间内没收到对端的任何响应,TIME_WAIT超时,进入CLOSED状态。
从上图中可以看出,client在发出server 端fin的ack以后,进入了time_wait的状态,知道2MSL以后,才会关闭。先来解释下2MSL,max segment lifetime,最大生成时间。MSL的值在一般的实现中取30s,有些实现采用2分钟。在TCP的状态机中的“被动关闭”,从CLOSE_WAIT到 LAST_ACK中有一个如下的规则:当T C P执行一个主动关闭,并发回最后一个A CK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可让TCP再次发送最后的ACK以防这个ACK丢失。个规则导致一个后果就是在 这个2MSL的时间内,该地址上的链接(客户端地址、端口和服务器端的地址、端口)不能被使用。比如我们在建立一个链接后关闭链接然后迅速重启链接,那么 就会出现端口不可用的情况。
2 time_wait状态的必要性
如果不考虑报文延迟、丢失,确认延迟、丢失等情况,TIME_WAIT的确没有存在的必要。当网络在不理想的情况下通常会有报文的丢失延迟发生,让我们看下面的一个特例:
客户端进入发送收到四次握手关闭的最后一个ACK后,进入TIME_WAIT同时发送ACK,如果其不停留2MSL时间,而是马上关闭连接,销毁连接上的资源,当发送如下情况时,将不能正常的完成四次握手关闭:
客户端发送的ACK在网路上丢失,这样服务器端收不到最后的ACK,重传定时器超时,将重传FIN到客户端,由于客户端关于该连接的所有资源都释放,收到重传的FIN后,它没有关于这个FIN的任何信息,所以向服务器端发送一个RST报文端,服务器端收到RST后,认为搞连接出现了异常(而非正常关闭)。
所以,在TIME_WAIT状态下等待2MSL时间端,是为了能够正确处理第一个ACK(最长生存时间为MSL)丢失的情况下,能够收到对端重传的FIN(最长生存时间为MSL),然后重传ACK。
是否只要主动关闭方在TIME_WAIT状态下停留2MSL,四次握手关闭就一定正常完成呢?
答案是否定的?可以考虑如下的情况,
TIME_WAIT状态下发送的ACK丢失,LAST_ACK时刻设定的重传定时器超时,发送重传的FIN,很不幸,这个FIN也丢失,主动关闭方在TIME_WAIT状态等待2MSL没收到任何报文段,进入CLOSED状态,当此时被动关闭方并没有收到最后的ACK。所以即使要主动关闭方在TIME_WAIT状态下停留2MSL,也不一定表示四次握手关闭就一定正常完成。
结论:在TIME_WAIT下等待2MSL,只是为了尽最大努力保证四次握手正常关闭。确保老的报文段在网络中消失,不会影响新建立的连接
考虑如下的情况,主动关闭方在TIME_WAIT状态下发送的ACK由于网络延迟的原因没有按时到底(但并没有超过MSL的时间),导致被动关闭方重传FIN,在FIN重传后,延迟的ACK到达,被动关闭方进入CLOSED状态,如果主动关闭方在TIME_WAIT状态下发送ACK后马上进入CLOSED状态(也就是没有等待)2MSL时间,则上述的连接已不存在:现在考虑下面的情况,假设上述的链接的四元组为(192.201.0.80:23,192.201.0.85:5555),由于连接已关闭,我们可以马上建立一个新的连接,并且这个连接的四元组也是(192.201.0.80:23,192.201.0.85:5555),那么当上一个连接的重传FIN到达主动关闭方时,被新的连接所接受,这将导致新的连接被复位,很显然,这不是我们希望看到的事情。
新的连接要建立,必须是在主动关闭方和被动关闭方都进入到CLOSED状态之后才有可能。所以,最有可能导致旧的报文段影响新的连接的情况是:
在TIME_WAIT状态之前,主动关闭方发送的报文端在网络中延迟,但是TIME_WAIT设定为2MSL时,这些报文端必然会在网络中消失(最大生存时间为MSL)。被动关闭方最有可能影响新连接的报文段就是我们上面讨论的情况,对方ACK延迟到达,在此之前重传的FIN,这个报文端发送之后,TIME_WAIT的定时器超时时间肯定大于MSL,在1MSL时间内,这个FIN要么在网络中因为生成时间到达而消失,要么到达主动关闭方被这确的处理,不会影响新建立的连接。