最常见的四次挥手的过程下图所示

image.png

  1. 客户端调用 close 方法,执行「主动关闭」,会发送一个 FIN 报文给服务端,从这以后客户端不能再发送数据给服务端了,客户端进入FIN-WAIT-1状态。FIN 报文其实就是将 FIN 标志位设置为 1。
  • FIN 段可携带数据
  • 半关闭状态

image.png

  1. 服务端收到 FIN 包以后回复确认 ACK 报文给客户端,服务端进入 CLOSE_WAIT,客户端收到 ACK 以后进入FIN-WAIT-2状态。
  2. 服务端也没有数据要发送了,发送 FIN 报文给客户端,然后进入LAST-ACK 状态,等待客户端的 ACK。同前面一样如果 FIN 段没有携带数据,也需要消耗一个序列号。
  3. 客户端收到服务端的 FIN 报文以后,回复 ACK 报文用来确认第三步里的 FIN 报文,进入TIME_WAIT状态,等待 2 个 MSL 以后进入 CLOSED状态。服务端收到 ACK 以后进入CLOSED状态。

为什么 FIN 报文要消耗一个序列号

image.png

为什么挥手要四次,变为三次可以吗?

可以是三次:

image.png

wireshark 抓包:

image.png

握手可以变为四次吗?

其实理论上完全是可以的,把三次握手的第二次的 SYN+ACK 拆成先回 ACK 包,再发 SYN 包就变成了「四次握手」

  • 握手的时候不携带数据, 没必要分成四次

image.png

同时关闭

可以两端同时发起 FIN 包:

image.png

以客户端为例:

  1. 最初客户端和服务端都处于 ESTABLISHED 状态
  2. 客户端发送 FIN 包,等待对端对这个 FIN 包的 ACK,随后进入 FIN-WAIT-1 状态
  3. 处于FIN-WAIT-1状态的客户端还没有等到 ACK,收到了服务端发过来的 FIN 包
  4. 收到 FIN 包以后客户端会发送对这个 FIN 包的的确认 ACK 包,同时自己进入 CLOSING 状态继续等自己 FIN 包的 ACK
  5. 处于 CLOSING 状态的客户端终于等到了ACK,随后进入TIME-WAIT
  6. 在TIME-WAIT状态持续 2*MSL,进入CLOSED状态

文字和图示不匹配, 应该以文字为准.