下图是TCP释放链接的四次挥手过程:
从下图中可以看出,客户端在收到了服务器端发来的结束报文段之后并没有直接进入CLOSE状态,而是转移到TIME_WAIT状态。在这个状态,客户端需要等待2MSL(Maximum Segment Life)最大报文生存时间段后才能完全关闭。
MSL是TCP报文段在网络中的最大生存时间,标准文档的建议值是2min,我在Ubuntu 14.04上测试的时间为30s
TIME_WAIT状态存在的原因:
1.可靠的终止TCP链接
2.保证让迟来的TCP报文短有足够的时间被识别并丢弃
在讨论原因之前我们先思考一下如果没有TIME_WAIT状态的存在会出现什么情况
1.如果没有TIME_WAIT状态的话,当客户端给服务端发送的确认报文丢失的话,那么服务端那边的计时器会超时,这个时候服务端会以为客户端没有收到服务端发送的结束报文,所以会再次发送,当然也会启动超时计时器;客户端将以复位报文短来回应服务器,服务器认为这是一个错误,因为它期望的是一个像TCP报文段连接断开确认的报文段。
2.在linux系统上,一个TCP端口不能被同时打开多次(2次及以上)。当一个TCP链接处于TIME_WAIT状态的时候,我们将无法立即使用该链接占用着的端口来建立一个新的连接。反过来思考,如果不存在TIME_WAIT状态,那么应用程序就能够立即创建一个和刚才关闭连接相似的链接(具有相同的IP地址和端口号)。这个新的 和原来相似的连接被称为原来的连接的化身。新的化身可能接收到属于原来的连接的携带应用程序数据的TCP报文段,这显然是不应该发生的,这就是TIME_WAIT存在的第二个原因。
另外,因为TCP报文段的最大生存时间是MSL,所以2MSL时间的TIME_WAIT状态能够确保网络上两个传输方向上尚未被接收到的 迟到的TCP报文段都已经消失(被中转路由器丢弃)。因此,一个链接的新的化身可以在2MSL时间之后安全的建立,而绝对不会收到属于原来连接的应用程序数据,这就是TIME_WAIT要保持2MSL时间段的原因.
下面我们来进行一次实验,当客户端断开连接后,不能立即启动和上次相似的连接(ip地址和端口)
如下图 在Ubuntu下面先把nginx打开 nginx 默认监听的是80端口 然后用nc(创建网络连接的工具)命令去访问本机的nginx服务器从图中可以看到当前进程被阻塞了,所以我们正在与服务器进行通信

然后我们再用netstat查看一下连接的状态 如下图可以看出为 ESTABLISHED状态 说明建立连接了
最后我们在第一张图所在的shell窗口内按Ctrl+c 终止当前通信 此时会发生tcp的四次挥手的过程,我们再看一下连接的状态可以看到状态为TIME_WAIT
此时我们再一次发起和上一次相似的(相同的ip和端口)的连接,可以发现绑定失败,此时这个套接字还在用,当然客户端我们可以使用其他的端口那样是可以建立连接的.