1)主机A发送位码为FIN=1,用来关闭客户A到服务器B的数据传送。此时A的状态为FIN_WAIT_1
2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。此时A为FIN_WAIT_2,B为CLOSE_WAIT
3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A。此时A为TIME_WAIT,B为LAST_ACK
4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。此时A、B都关闭了,状态变为CLOSED。
当(2)、(3)步中的ACK和FIN在一个包中发送时,A的状态会直接从FIN_WAIT_1变为TIME_WAIT
为什么建立连接需要三次握手,而断开连接需要四次握手?
因为每个方向都需要一个FIN和ACK,当一端发送了FIN包之后,处于半关闭状态,此时仍然可以接收数据包。
在建立连接时,服务器可以把SYN和ACK放在一个包中发送。
但是在断开连接时,如果一端收到FIN包,但此时仍有数据未发送完,此时就需要先向对端回复FIN包的ACK。等到将剩下的数据
都发送完之后,再向对端发送FIN,断开这个方向的连接。
因此很多时候FIN和ACK需要在两个数据包中发送,因此需要四次握手
中各种状态的含义
FIN_WAIT_1: 这个状态要好好解释一下,其实 FIN_WAIT_1 和 FIN_WAIT_2 状态的真正含义都是表示等待对方的 FIN 报文。而这两
种状态的区别是:FIN_WAIT_1 状态实际上是当 SOCKET 在 ESTABLISHED 状态时,它想主动关闭连接,向对方发送了 FIN 报文,此
时该 SOCKET 即进入到 FIN_WAIT_1 状态。而当对方回应 ACK 报文后,则进入到 FIN_WAIT_2 状态,当然在实际的正常情况下,无
论对方何种情况下,都应该马 上回应 ACK 报文,所以 FIN_WAIT_1 状态一般是比较难见到的,而 FIN_WAIT_2 状态还有时常常可
以用 netstat 看到。
FIN_WAIT_2:上面已经详细解释了这种状态,实际上 FIN_WAIT_2 状态下的 SOCKET,表示半连接,也即有一方要求 close 连接,但
另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。
TIME_WAIT: 表示收到了对方的 FIN 报文,并发送出了 ACK 报文,就等 2MSL 后即可回到 CLOSED 可用状态了。如果 FIN_WAIT_1
状态下,收到了对方同时带 FIN 标志和ACK 标志的报文时,可以直接进入到 TIME_WAIT 状态,而无须经过 FIN_WAIT_2 状态。
CLOSING(图中没有标志这种状态): 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当
你发送 FIN 报文后,按理来说是应该先收到(或同时收到)对方的 ACK 报文,再收到对方的 FIN 报文。但是 CLOSING 状态表示
你发送 FIN 报文后,并没有收到对方的 ACK 报文,反而却也收到了对方的 FIN 报文。什么情况下会出现此种情况呢?其实细想一
下,也不难得出结论:那就是如果双方几乎在同时close一个 SOCKET 的话,那么就出现了双方同时发送 FIN 报文的情况,也即会出
现 CLOSING 状态,表示双方都正在关闭 SOCKET 连接。
CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方 close 一个 SOCKET 后发送 FIN 报文给自己,你系统毫
无疑问地会回应一个 ACK 报文给对方,此时则进入到 CLOSE_WAIT 状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还
有数据发送给对方,如果没有的话,那么你也就可以 close 这个 SOCKET,发送 FIN 报文给对方,也即关闭连接。所以你在 CLOSE_WAIT
状态下,需要完成的事情是等待你去关闭连接。
LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送 FIN 报文后,最后等待对方的 ACK 报文。当收到 ACK 报文后
,也即可以进入到 CLOSED 可用状态了。
原文:http://blog.51cto.com/12222886/2069672