目录

HTTP 三次握手与四次挥手

可以先按照较为理想情况学习。学完后在看待握手和挥手的问题时,要假设每一个消息都可能丢失。

另外握手要特别注意服务端为连接分配资源的问题。

三次握手

  1. 客户端:发起连接请求

  2. 服务端:分配资源,将其加入半连接队列,响应 ACK

  3. 客户端:分配资源,响应 ACK。可附带数据。

SYN 攻击(DDoS 攻击的一种)所用的客户端只执行第一步,不执行第三步。使得流程只执行到第二步。
如果半连接队列满了,新来的 SYN 请求会被丢弃。

第三步的另一个作用:

由于服务端很晚才收到客户端的连接请求,所以客户端发现第一步的请求超时,会再次发送。如果没有第三步,先前发送的连接请求有可能在连接关闭后才到达服务端,此时服务端分配资源。但由于服务端发送 ACK 后客户端没有执行第三步(因为客户端确实不想要再连接了),服务端在等待超时后释放资源。

四次挥手

  1. 客户端:发送关闭请求,表示无更多请求。

  2. 服务端:收到客户端关闭请求。服务端继续返回数据。

  3. 服务端:发送关闭请求,表示无更多数据可以返回。

  4. 客户端:收到服务端关闭请求,发送确认。等待 2MSL 后关闭。

这个表示无更多请求的行为,可以联想到 Golang 中关闭 Channel。关闭 Channel 只表示不会继续往 Channel 里面存放数据,但仍然可以被消费,直到 Channel 为空。

为什么等 2MSL

MSL(Maximum Segment Lifetime)

因为如果服务端没有收到客户端的确认,会重传关闭请求。客户端会在 2MSL 之内收到服务端的重传。

如果超过了 2MSL ,则客户端默认服务端已收到了 LAST-ACK。

客户端每次收到服务端重传并发送 LAST-ACK 后,会重制计时。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
                              +---------+ ---------\      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  |
                              +---------+                   +---------+

https://tools.ietf.org/html/rfc793

https://pic2.zhimg.com/80/v2-7c402fde8210519feb8f65d41410c205_720w.jpg

如果服务端一直重传,在客户端 2MSL 后也没有收到 LAST-ACK ,会怎么样?

服务端会在发送 FIN 后,碰到以下三种情况的任意一种时关闭连接:

  • 收到客户端的 LAST-ACK
    • 正常情况。客户端收到 FIN 后发送
  • 收到客户端的 RST
    • 客户端发送 LAST-ACK 没有被服务端收到,并且 2MSL 内没有收到服务端的 FIN,关闭了连接。 2MSL 后收到服务端的 FIN 时,发送 RST。
  • 重传超时
    • 重传的上限

参考

https://zhuanlan.zhihu.com/p/86426969

https://www.zhihu.com/question/27564314/answer/162476313

https://www.jianshu.com/p/ff26312e67a9