TCP 握手和挥手进一步理解

握手

序号与确认

TCP 所有的报文都需要携带一个序号 seq,用于确保接收的顺序,避免丢包重包。这个序号是一个随机数,并非从零开始,但是在使用中往往会用当前序号减去初始序号,显示一个偏移量作为相对序号。序号本身代表的含义是,当前数据包负载部分的第一个字节,在整个实际数据中的位置。以发送 Hello World! 为例,如果其被拆分成两个包 Hello World!,那么这两个包的相对序号将是 0 和 3。

从 TCP 头部可知,序号最大为 4G4G,但由于序号可以循环重复使用,每个报文实际存活时间有限(180180 秒),因此除非带宽达到 180180 秒传输 4G4G 的数据(22M/s22 M/s),否则 TCP 本身就可以做到不冲突。同时,TCP 头部的扩充字段可以通过设置时间戳来进一步避免冲突,因此即使超过 22M/s22 M/s 仍然可以正常使用 TCP

seq 对应的是 ack,其表示自己已经收到了所有 seq<ackseq \lt ack 的包,属于对对方数据的确认。换种方式理解,其也是自己所期望的对方下一个包 seq 的值

什么是三次握手

要想解释三次握手,首先需要解释三次握手是什么

TCP 是一个 可靠有连接 传输协议
要确保可靠性,需要 确保对方能收到自己的信息
要确保有连接,需要 建立会话

而握手要解决的就是这两个问题,当然,顺带还确定了对方真的是在用 TCP 协议(毕竟存在双方用不同的协议,还 “凑巧” 能理解对方的情况的)

三次握手实际上是通过对对方序号的确认,来实现了连接建立

  1. 客户端发起连接,发送报文SYN=1,seq=x
  2. 服务端收到请求后如果接收连接,则返回SYN=1,seq=y,ack=x+1
  3. 客户端确认收到连接,如果已有数据需要发送则发送seq=x+1,ack=y+1,并携带对应的数据;否则发送seq=x,ack=y+1

前两个数据包携带SYN字段,即使不携带数据,序号也需要加 1
由于第二步服务端就已经分配资源,因此如果有大量握手请求,会导致 SYN 泛洪攻击

为什么是三次握手

首先,给出标准答案

The principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.

大概意思是,为了避免序号错误的问题。假设如下情况:
发起者 A 向服务端 B 发起了 TCP 握手(第一个第一次握手),等了几秒钟还没有结果,于是他决定重新发起 TCP 连接(第二个第一次握手)。
在第二个第一次握手到达服务端 B 前,服务端 B 终于发现自己有个请求没处理,于是他开始处理握手请求(第一个第二次握手)。
这时,对 A 而言,其第一个握手已经结束,现在是第二个握手流程,也即 A 第二个握手与 B 第一个握手对接上了!

结果就是两个人都以为对方理解了自己的思路,但实际上在两个频道说话……


上面的解释,没有问题,但是可以从另一个方向理解三次握手

如果将通信简单划分为可以通信和无法通信,那么实际上一个 TCP 连接有四种可能:

  • A 无法发送给 B,B 无法发送给 A
  • A 可以发送给 B,B 无法发送给 A
  • A 无法发送给 B,B 可以发送给 A
  • A 可以发送给 B,B 可以发送给 A

握手的任务就是让 A、B 双方都确认对方知道了双方都可以通信。

第一次握手,A 不知道对方有没有收到,因此 A 什么都不知道。B 收到了 A 的消息,因此他知道 A->B 是连通的
第二次握手,A 在收到 B 的消息时,知道了 A→B 连通(不然 B 不会返回消息),B->A 也连通(不然自己收不到)。但是 B 由于不知道 A 是否已经收到,因此他只知道 A→B 连通
第三次握手,B 收到 A 的确认,B 知道 B→A 也是连通的,双方都确认通信没有问题

挥手

  1. 某一方希望关闭连接,向对端发送释放报文段FIN=1,ACK=1,seq=u,并停止发送数据
  2. 对端接收到后发送确认ACK=1,seq=v,ack=u+1
  3. 发起方不再发送数据,对端可能还需要发送数据,TCP 处于半关闭状态
  4. 对端也没有需要发送的数据时,发送释放报文段FIN=1,ACK=1,seq=w,ack=u+1
  5. 发起方确认ACK=1,seq=u+1,ack=w+1。发送报文 2MSL 后,连接关闭(可能会存在确认报文发送失败,对端请求重传的情况)

与三次握手类似,FIN 即使不携带数据,序号也需要加 1
四次挥手顺序不定,只需要满足响应在对应的请求后即可

为什么是四次

四次挥手类似三次握手,需要确认:A 已经关闭,并且 B 也已经关闭

第一次挥手,A 发送关闭请求,B 知道 A 准备关闭
第二次挥手,B 发送确认,A 知道 B 已经知道自己准备关闭,因此 A 停止发送数据(但还要接收,因为 B 还未关闭)
第三次挥手,B 发送关闭请求,A 知道 B 也准备关闭(到这时,双方都已经确认对方准备关闭,因此除去最后的确认外,几乎已经完全关闭)
第四次挥手,A 发送确认,B 知道 A 已经知道自己准备关闭,此时 B 也可以正式关闭

原理上来说,三次握手其实应该和四次挥手一样,为四次握手。但是由于第二次握手不需要传输数据,因此 B 发送给 A 的确认以及 B 请求建立连接两条报文可以合并为一次。而关闭连接时期,由于另一方可能还需要发送数据,因此无法合并。

抓包

网络问题,抓包解释一切妖魔鬼怪,下面是一个三次握手后直接四次挥手的会话(数据包包含 IPv4 包,seq 除去前两个握手使用的是相对序号)

$ tcpdump -A -t -ns 0 -X -r a.pcap

reading from file a.pcap, link-type EN10MB (Ethernet), snapshot length 262144
IP 127.0.0.1.43402 > 127.0.0.1.6666: Flags [S], seq 916859721, win 65495, options [mss 65495,sackOK,TS val 2545404621 ecr 0,nop,wscale 7], length 0
        0x0000:  4500 003c 7b94 4000 4006 c125 7f00 0001  E..<{.@.@..%....
        0x0010:  7f00 0001 a98a 1a0a 36a6 2b49 0000 0000  ........6.+I....
        0x0020:  a002 ffd7 fe30 0000 0204 ffd7 0402 080a  .....0..........
        0x0030:  97b7 cacd 0000 0000 0103 0307            ............
IP 127.0.0.1.6666 > 127.0.0.1.43402: Flags [S.], seq 3047146258, ack 916859722, win 65483, options [mss 65495,sackOK,TS val 2545404622 ecr 2545404621,nop,wscale 7], length 0
        0x0000:  4500 003c 0000 4000 4006 3cba 7f00 0001  E..<..@.@.<.....
        0x0010:  7f00 0001 1a0a a98a b59f c312 36a6 2b4a  ............6.+J
        0x0020:  a012 ffcb fe30 0000 0204 ffd7 0402 080a  .....0..........
        0x0030:  97b7 cace 97b7 cacd 0103 0307            ............
IP 127.0.0.1.43402 > 127.0.0.1.6666: Flags [.], ack 1, win 512, options [nop,nop,TS val 2545404622 ecr 2545404622], length 0
        0x0000:  4500 0034 7b95 4000 4006 c12c 7f00 0001  E..4{.@.@..,....
        0x0010:  7f00 0001 a98a 1a0a 36a6 2b4a b59f c313  ........6.+J....
        0x0020:  8010 0200 fe28 0000 0101 080a 97b7 cace  .....(..........
        0x0030:  97b7 cace                                ....
IP 127.0.0.1.6666 > 127.0.0.1.43402: Flags [F.], seq 1, ack 1, win 512, options [nop,nop,TS val 2545404622 ecr 2545404622], length 0
        0x0000:  4500 0034 58e5 4000 4006 e3dc 7f00 0001  E..4X.@.@.......
        0x0010:  7f00 0001 1a0a a98a b59f c313 36a6 2b4a  ............6.+J
        0x0020:  8011 0200 fe28 0000 0101 080a 97b7 cace  .....(..........
        0x0030:  97b7 cace                                ....
IP 127.0.0.1.43402 > 127.0.0.1.6666: Flags [.], ack 2, win 512, options [nop,nop,TS val 2545404628 ecr 2545404622], length 0
        0x0000:  4500 0034 7b96 4000 4006 c12b 7f00 0001  E..4{.@.@..+....
        0x0010:  7f00 0001 a98a 1a0a 36a6 2b4a b59f c314  ........6.+J....
        0x0020:  8010 0200 fe28 0000 0101 080a 97b7 cad4  .....(..........
        0x0030:  97b7 cace                                ....
IP 127.0.0.1.43402 > 127.0.0.1.6666: Flags [F.], seq 1, ack 2, win 512, options [nop,nop,TS val 2545405622 ecr 2545404622], length 0
        0x0000:  4500 0034 7b97 4000 4006 c12a 7f00 0001  E..4{.@.@..*....
        0x0010:  7f00 0001 a98a 1a0a 36a6 2b4a b59f c314  ........6.+J....
        0x0020:  8011 0200 fe28 0000 0101 080a 97b7 ceb6  .....(..........
        0x0030:  97b7 cace                                ....
IP 127.0.0.1.6666 > 127.0.0.1.43402: Flags [.], ack 2, win 512, options [nop,nop,TS val 2545405622 ecr 2545405622], length 0
        0x0000:  4500 0034 0000 4000 4006 3cc2 7f00 0001  E..4..@.@.<.....
        0x0010:  7f00 0001 1a0a a98a b59f c314 36a6 2b4b  ............6.+K
        0x0020:  8010 0200 0ba4 0000 0101 080a 97b7 ceb6  ................
        0x0030:  97b7 ceb6   

参考文献