49

网络知识(1) - TCP连接关闭四次挥手

 4 years ago
source link: https://www.tuicool.com/articles/vuUVVzA
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

iIBZb2A.jpg!web

本文包含内容:

  • TCP FIN 简介
  • TCP ACK 简介
  • 为什么 TCP 连接关闭是四次挥手
  • 先看最常见的正常关闭流程
  • 什么时候进入 CLOSING 状态
  • TIME_WAIT 状态的作用
  • 为什么 被动关闭端 不需要维持一个类似 TIME_WAIT 的状态,万一发出的 ACK 也丢失了呢
  • 最后,再奉上一张 geek 味十足的tcp状态迁移图

TCP FIN 简介

FIN可以理解为TCP包中的一种信令类型。事实上,FIN是TCP包头中的一个固定标志位,该标志位为1时,表示本端关闭连接。

TCP ACK 简介

TCP基于IP协议,IP包不保证可靠传输。

TCP的做法是,发送端发送的每个TCP包携带序号信息,接收端通过序号处理乱序包和重复包。

并且,接收端持续向发送端发送ACK信息,反馈接收端接收到的流式数据的位置,从而使得发送端有能力检测出对端未接收到数据,发送端可重新发送丢失的数据。

为什么 TCP 连接关闭是四次挥手

由于TCP可双向发送数据,所以TCP连接关闭至少需要两次挥手,即两端各自发送FIN,表示本端已无数据需要发送。

又由于FIN包也有丢失的可能,所以出现了ACK of FIN,即对FIN包也回复ACK确认,以保证FIN包丢失后可以重传。

事实上,由于FIN和ACK of FIN都有可能丢失,TCP连接关闭的设计比四次挥手通常被理解的情况要更复杂些。

我们接下来看。

先看最常见的正常关闭流程

提示,本文的后续内容建议结合上面的 TCP连接关闭状态连接图 配套食用。

以下 主动关闭端 指未收到对端FIN的情况下本端发送FIN。 被动关闭端 则是先收到对端发送的FIN,之后某个时间点本端发送FIN。

主动关闭端

流程为: 发送FIN,接收ACK,接收FIN,发送ACK

状态迁移为: ESTAB -> FINWAIT_1 -> FINWAIT_2 -> TIME_WAIT -> CLOSED

被动关闭端

流程为: 接收FIN,发送ACK,发送FIN,接收ACK

状态迁移为: ESTAB -> CLOSE_WAIT -> LAST_ACK -> CLOSED

什么时候进入 CLOSING 状态

有两种情况:

第一种,由于ACK of FIN可能丢失,所以当 被动关闭端 发出的ACK丢失,而 被动关闭端 紧接着又发出了FIN,那么 主动关闭端 会先收到FIN,从而进入 CLOSING 状态。

第二种,两端都在还未收到FIN的的情况,发出了FIN,即两端同时关闭,那么可能出现发出FIN后还没收到对应的ACK,立马就收到对端发出的FIN。第二种情况下,两端都是 主动关闭端 ,它们都是首先从 ESTAB 状态进入 FINWAIT_1 状态,不再走 CLOSE_WAIT 那条状态迁移路线。

TIME_WAIT 状态的作用

简单来说,由于ACK of FIN存在丢失的可能。 主动关闭端被动关闭端 回复的ACK of FIN可能丢失(此ACK为 主动关闭端 发出的最后一个包)。而TCP是不会再去对ACK做ACK确认的。

那么如果出现 主动关闭端 发出的ACK丢失了的情况, 被动关闭端 由于收不到ACK将停留在 LAST_ACK 状态,无法进入 CLOSED 状态。

TCP协议处理这种异常情况的做法是: 被动关闭端 如果收不到ACK将触发超时重新发送FIN;在 主动关闭端 维持一个 TIME_WAIT ,继续接收FIN并作出ACK回复。

TIME_WAIT 的维持时间是2个MSL,MSL是Maximum Segment Lifetime的缩写,即报文最大生存时间。

其实讲到这我们已经可以知道,作为 主动关闭端 ,进入 TIME_WAIT 状态并维持一段时间是TCP协议本身的设计,并不是一种异常状态。

之后我会再单独针对 TIME_WAIT 写一篇文章,描述 TIME_WAIT 的维持时间为什么是2个MSL, TIME_WAIT 的一些内核相关参数的设置,以及服务器上出现大量 TIME_WAIT 时我们应该怎么办。

为什么 被动关闭端 不需要维持一个类似 TIME_WAIT 的状态,万一发出的 ACK 也丢失了呢

我在学习TCP连接关闭时,有一个疑问,既然 主动关闭端 为了解决发送的ACK丢失,维持了一个 TIME_WAIT 状态。

那么 被动关闭端 发出的ACK也可能丢失,如果这个ACK丢失(其他包都未丢失), 被动关闭端 会顺利进入 CLOSED 状态,那么 主动关闭端 岂不是会一直停留在 CLOSING 状态。

后来在网上询问了一些高手,他们的解释是并不会出现这种情况。

理解这个问题,首先要理解ACK of FIN可以是一个单独的TCP包,也可以不是。

事实上,ACK信息也是TCP包头中的一个固定字段。

所以,当 被动关闭端 关闭连接发送FIN时,FIN中的ACK字段也会携带对端发出FIN所对应的ACK信息。只要 主动关闭端 收到了这个FIN,也即可以确认对端已经收到了本端发出的FIN。

这种情况下,可以理解为 主动关闭端FINWAIT_1 收到FIN后,进入 CLOSING 状态,之后迅速进入了 TIME_WAIT 状态。

最后,奉上一张geek味十足的tcp状态迁移图

图片来源: RFC 793 - Transmission Control Protocol ( https://tools.ietf.org/html/rfc793 )

另外从中可以看到, SYN_RCVD 状态也可以发送FIN从而进入 FINWAIT_1

                             +---------+ ---------\      active OPEN
                             |  CLOSED |            \    -----------
                             +---------+<---------\   \   create TCB
                               |     ^              \   \  snd SYN
                  passive OPEN |     |   CLOSE        \   \
                  ------------ |     | ----------       \   \
                   create TCB  |     | delete TCB         \   \
                               V     |                      \   \
                             +---------+            CLOSE    |    \
                             |  LISTEN |          ---------- |     |
                             +---------+          delete TCB |     |
                  rcv SYN      |     |     SEND              |     |
                 -----------   |     |    -------            |     V
+---------+      snd SYN,ACK  /       \   snd SYN          +---------+
|         |<-----------------           ------------------>|         |
|   SYN   |                    rcv SYN                     |   SYN   |
|   RCVD  |<-----------------------------------------------|   SENT  |
|         |                    snd ACK                     |         |
|         |------------------           -------------------|         |
+---------+   rcv ACK of SYN  \       /  rcv SYN,ACK       +---------+
  |           --------------   |     |   -----------
  |                  x         |     |     snd ACK
  |                            V     V
  |  CLOSE                   +---------+
  | -------                  |  ESTAB  |
  | snd FIN                  +---------+
  |                   CLOSE    |     |    rcv FIN
  V                  -------   |     |    -------
+---------+          snd FIN  /       \   snd ACK          +---------+
|  FIN    |<-----------------           ------------------>|  CLOSE  |
| WAIT-1  |------------------                              |   WAIT  |
+---------+          rcv FIN  \                            +---------+
  | rcv ACK of FIN   -------   |                            CLOSE  |
  | --------------   snd ACK   |                           ------- |
  V        x                   V                           snd FIN V
+---------+                  +---------+                   +---------+
|FINWAIT-2|                  | CLOSING |                   | LAST-ACK|
+---------+                  +---------+                   +---------+
  |                rcv ACK of FIN |                 rcv ACK of FIN |
  |  rcv FIN       -------------- |    Timeout=2MSL -------------- |
  |  -------              x       V    ------------        x       V
   \ snd ACK                 +---------+delete TCB         +---------+
    ------------------------>|TIME WAIT|------------------>| CLOSED  |
                             +---------+                   +---------+

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK