我们知道四次握手是这样的(假定是 client 先 close 的):
client 调用 close。TCP 协议会发送 FIN x 给 server
server 收到 FIN x 之后,会回复 ack x+1
接着、server 调用 close,给客户端发送 FIN y
最后,客户端回复 ack y+1
分析与状态的关系:
1)client 调用 close,发送了 FINx。client 进入
fin_wait1状态。server 收到并回复 ack,server 进入
close_wait状态。然后 client 会收到 ack,进入
fin_wait2状态
2)server 接着调用 close,给 client 发送了 fin,server 则进入了了
last_ack状态。
3)client 收到 FIN 之后,回复 ack。client 进入 time_wait 状态。server 收到 ack 之后,进入
closed状态。
(
client 在保持了 2 个 MSL之后就进入
closed状态)
1)
client 进入 time_wait 状态之后,会保持在这个状态 2MSL。目的是为了确保发送过去的 ack 可以被收到(因为后面已经没有数据可以发送了)。
2)连接过程是状态的改变,促使状态的改变是用户的调用。所以切换状态不一定是用户的调用。(比如,server 进入 close_wait 状态,纯粹是 TCP 协议做好的,用户并没有调用什么接口)
3)关于退出时的分析,存在一个主动一个被动关系。上面分析的 client 主动,则 client 会出现
fin_wait1、fin_wait2、time_wait 状态。server 会出现
close_wait、last_ack状态。
如果是 server 主动断开的,则关系刚刚反过来了。server 先进入
fin_wait1状态,然后是
fin_wait2状态。后面整个就反过来了。
通过上面的分析我们知道,client 主动退出时,先给 server 发送了一个 FIN。接着会收到一个 ack 确认这个 FIN。
这种情况是怎么出现的呢:那就是双方几乎同时 closer 一个 socket。这是双方都正在关闭 socket 连接。这种情况出现的几率很小
首先我们知道,TCP 协议是去全双工的。可以在发送的同时进行接收数据。
假定是主机 A 和主机 B 进行通信,断开时是 A 主动断开的。
1)三次握手:第一次握手表明 A 可以发数据给 B。但是无法保证 B 发给 A 的数据可以被收到。所以 B 也需要发送 SYN 给 A,A 对它进行回应,才保证了 B 也可以发数据给 A。
个人理解可以把三步拆分为四步理解:
a)主机 A 给 B 发送 SYN
b)主机 B 回复 ack --- 这时表明 A 可以发数据给 B
c)主机 B 发送 SYN 给 A
d)主机 A 回复 ack --- 这时表明 B 也可以发送数据给 A
2)四次握手,就像下面这样理解:
a)主机 A 给 B 发送 FIN,表示对 B 说 "我要断开了"
b)主机 B 回复 ack 进行确认,表示对 A 说 "嗯,我知道了,你可以断开了"
c)然后 B 发送 FIN 给 A,表示对 A 说 "A,我也要断开了"
d)A 回复 ack 进行确认,表示对 B 说:"嗯,知道了,你断开吧"
前两步对 A 进行断开,后两步对 B 进行断开。
就拿上面的例子来说,假如 A 断开了通知 B,但是 B 还有数据没有发送完毕,如果立即断开(调用 close 发送 FIN),就无法保证数据的可靠性。
如果等数据发送完毕再将 fin 和 ack 一起发过去,n 那么 A 就会长时间处于 fin_wait1 状态。这样就比较不好了。
实际情况中我们可能会在 server 忘记关闭客户端的 socket。那么 client 就会一直处于 fin_wait2 状态,越来越多的 fin_wait2 状态会导致系统崩溃。所以我们需要在编程中要注意在什么情况下要关闭双方的 socket。
来源: http://www.cnblogs.com/xcywt/p/8082428.html