Skip to content
On this page

TCP 的三次握手,也是需要确认双方的两样能力: 发送的能力和接收的能力。于是便会有下面的三次握手的过程:

握手过程

刚开始客户端处于 Closed 的状态,服务端处于 Listen 状态。 进行三次握手:

握手描述
1️⃣客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN(c)。此时客户端处于 SYN_SEND 状态。
2️⃣服务器收到客户端的 SYN 报文之后,会以自己的 SYN + ACK 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s)。 同时会把客户端的 ISN + 1 作为 ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态。
3️⃣客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。

从图中可以看出,SYN 是需要消耗一个序列号的,下次发送对应的 ACK 序列号要加 1,为什么呢?只需要记住一个规则:

凡是需要对端确认的,一定消耗 TCP 报文的序列号。

SYN 需要对端的确认, 而 ACK 并不需要,因此 SYN 消耗一个序列号而 ACK 不需要。

为什么需要三次握手,两次不行吗?

试想如果是用两次握手,则会出现下面这种情况:

如果是两次,你现在发了 SYN 报文想握手,但是这个包滞留在了当前的网络中迟迟没有到达,TCP 以为这是丢了包,于是重传,两次握手建立好了连接。

看似没有问题,但是连接关闭后,如果这个滞留在网路中的包到达了服务端呢?这时候由于是两次握手,服务端只要接收到然后发送相应的数据包,就默认建立连接,但是现在客户端已经断开了。

看到问题的吧,这就带来了连接资源的浪费。

三次握手过程中可以携带数据吗?

第三次握手的时候,可以携带。前两次握手不能携带数据。

如果前两次握手能够携带数据,那么一旦有人想攻击服务器,那么他只需要在第一次握手中的 SYN 报文中放大量数据,那么服务器势必会消耗更多的时间和内存空间去处理这些数据,增大了服务器被攻击的风险。

第三次握手的时候,客户端已经处于 ESTABLISHED 状态,并且已经能够确认服务器的接收、发送能力正常,这个时候相对安全了,可以携带数据。

同时打开会怎样?

如果双方同时发 SYN 报文,状态变化会是怎样的呢?

这是一个可能会发生的情况。

状态变迁如下:

在发送方给接收方发 SYN 报文的同时,接收方也给发送方发 SYN 报文,两个人刚上了!

发完 SYN,两者的状态都变为 SYN-SENT

在各自收到对方的 SYN 后,两者状态都变为 SYN-REVD

接着会回复对应的 ACK + SYN,这个报文在对方接收之后,两者状态一起变为 ESTABLISHED

这就是同时打开情况下的状态变迁。

Released under the MIT License.