TCP 的三次握手、四次挥手
要弄清 TCP 建立连接需要几次交互才行,我们需要弄清建立连接进行初始化的目标是什么。TCP 进行握手初始化一个连接的目标是:分配资源、初始化序列号(通知 peer 对端我的初始序列号是多少),知道初始化连接的目标,那么要达成这个目标的过程就简单了,握手过程可以简化为下面的四次交互【总共发送了三个包,3和4是同一个包】:
1)client 端首先发送一个 SYN 包告诉 Server 端我的初始序列号是 X;
2)Server 端收到 SYN 包后回复给 client 一个 ACK 确认包,告诉 client 说我收到了;
3)接着 Server 端也需要告诉 client 端自己的初始序列号,于是 Server 也发送一个 SYN 包告诉 client 我的初始序列号是 Y;
4)Client 收到后,回复 Server 一个 ACK 确认包说我知道了。
整个过程 4 次交互即可完成初始化,但是,细心的同学会发现两个问题:
- Server 发送 SYN 包是作为发起连接的 SYN 包,还是作为响应发起者的 SYN 包呢?怎么区分?比较容易引起混淆
- Server 的 ACK 确认包和接下来的 SYN 包可以合成一个 SYN ACK 包一起发送的,没必要分别单独发送,这样省了一次交互同时也解决了问题[1].这样 TCP 建立一个连接,三次握手在进行最少次交互的情况下完成了 Peer 两端的资源分配和初始化序列号的交换。
大部分情况下建立连接需要三次握手,也不一定都是三次,有可能出现四次握手来建立连接的。如下图,当 Peer 两端同时发起 SYN 来建立连接的时候,就出现了四次握手来建立连接(对于有些 TCP/IP 的实现,可能不支持这种同时打开的情况)。
TCP 进行断开连接的目标是:回收资源、终止数据传输。由于 TCP 是全双工的,需要 Peer 两端分别各自拆除自己通向 Peer 对端的方向的通信信道。这样需要四次挥手来分别拆除通信信道,就比较清晰明了了。
1)Client 发送一个 FIN 包来告诉 Server 我已经没数据需要发给 Server 了;
2)Server 收到后回复一个 ACK 确认包说我知道了;
3)然后 server 在自己也没数据发送给 client 后,Server 也发送一个 FIN 包给 Client 告诉 Client 我也已经没数据发给 client 了;
4)Client 收到后,就会回复一个 ACK 确认包说我知道了。
到此,四次挥手,这个 TCP 连接就可以完全拆除了,简单翻译成通俗的就是:
- 第一次:客户端请求断开
- 第二次:服务器确认客户端的断开请求
- 第三次:服务器请求断开
- 第四次:客户端确认服务器的断开