我们都知道,在面试中,TCP三握手是被考察很频繁的一个知识点。所以我们要对其中的过程了解的比较透彻,我们必须要清楚其中几次握手中的状态转变、作用等等。
下面我想就三握手的过程、作用以及相关问题进行讲述。
1. 三握手的过程

刚开始客户端处于closed状态,服务端处于listen状态。
- 第一次握手:客户端给服务端发送一个
SYN报文,并且指明了客户端的初始序列号**seq=x**。此时客户端处于**SYN_Send**状态。 - 第二次握手:服务器收到客户端的
SYN报文后,会以自己的SYN报文作为回答,并且指定了自己的初始序列号**seq=y**,同时将客户端传来的序列号x+1作为**ack**的值,表示自己收到了客户端的SYN,此时服务器处于**SYN_REVD**的状态。此时确认了客户端的发送能力与服务器端的接收、发送能力没有问题。 - 第三次握手:客户端收到服务端发来的
SYN报文后,会发送一个ACK报文。然后一样把服务器的序列号y+1作为ack的值,表示已经收到了服务端的报文,此时客户端处于established状态。 - 当服务器收到
ACK报文后,也处于established状态,此时确认了客户端的接收能力正常,双方建立了连接。
2. 三握手的作用
- 确认双方的接收、发送能力是否正常;
- 指定自己的初始化序列号,为后续的可靠运输做准备;
3. 相关问题
- seq 是固定的吗?
由于三握手的作用之一就是客户端与服务端双方交换 ISN,以便让对方了解接下来接收数据的时候如何按照序列号组装数据。如果 ISN 固定则很容易被攻击者猜到后续的确认号,因此 ISN 为动态生成。
- 什么是半连接队列
当服务器完成第二次握手时,处于SYN_RCVD状态。服务器会把此种状态下的请求连接放到一个队列里,这种队列就是所谓的半连接队列。在服务器发送完SYN-ACK包后,如果未收到客户确认包,服务器进行重传,当重传次数超过系统规定的最大重传次数,系统将会从半连接队列中删除该连接信息。
顺便说一下,当完成三握手建立起连接,请求就会放在所谓的全连接队列中。当队列满了就有可能出现丢包现象。
- 三握手过程可以携带数据吗?
第一、第二次握手不可以携带数据,第三次握手可以携带数据。
如果前两次握手可以携带数据,如果有人恶意攻击服务器,在SYN报文中放入大量的数据的同时疯狂发送报文,这将导致服务器花费很多时间、空间去接受报文。即前两次携带数据将会导致服务器更为容易受到攻击。
在第三次握手中,客户端已经处于established状态,即对客户端而言已经建立起连接。与ACK报文一同发送数据给服务器后,服务器在收到后报文后处于established状态,可以对数据进行处理。
