什么是三次握手?
为了准确无误地把数据发送到目标处,TCP采用了三次握手的策略。简而言之,三次握手就是用来建立连接的。
那么三次握手双方都说了什么呢?
:::info
A:喂,听得到吗?我的数据从序号x开始编号(SYN)
B:好的,我知道了,我的数据从序号y开始编号(SYN-ACK)
A:好的,我知道了,我们开始通话吧(ACK)
:::
所以说,三次握手的过程中,不是你能不能听得到,而是协商双方开始的序号。
- 首先客户端发送一个SYN报文段,这个报文只有SYN被置1。另外这个报文是不携带数据的,但是它占用一个序号,意味着下次发送数据序列号要加一。客户端会随机生成一个序列号。
:::warning
为什么SYN要占用一个序列号呢? 不占用序列号的段是不需要确认的。它里面都没内容你还确认个啥?比如ACK段。SYN段是需要对方确认的,所以要占一个序列号。
:::
- 服务端收到客户端的SYN的报文以后,将SYN+ACK都置位,发送给客户端。SYN的作用也是同步告知服务端生成的初始序号。ACK的作用是告知客户端你发送的SYN已经收到了,并指定下一个数据段的起始序号是多少。虽然也没有携带数据,但因为SYN需要被确认,所以也要占用一个序列号。
- 客户端最后发送一个ACK段。这个段用来确认服务端发送的SYN段。因为这个ACK段不携带任何数据,也不需要被确认,所以不占用序列号。
为什么是3次?
协商一个序号的过程按理说需要一个来回来完成,也就是2次。所以理论上建立连接需要2个来回(4次),互相确认双方的初始序号(Initial Sequence Number,ISN)。
但是第二个来回的告知和上一次的确认可以合在一起发送(SYN + ACK),所以只需要三次握手,就可以建立TCP连接。
这也解释了为什么不能只有 2 次握手:因为只能协商一个序号。
在日常应用场景中,丢包率不高,因此三次握手是最合理的做法,少了不够,多了白搭。
丢包了怎么办?
SYN+ACK丢包的话,发送方在等待超时后重传SYN包即可解决。
ACK丢包的话:
初始的状态是处于
ClOSED状态。这里的ClOSED不是一个真实的状态,而是一个假想的起点和终点。- 客户端调用connect以后会发送SYN同步报文给服务端,然后进入
SYN-SENT状态,客户端将保持这个状态,直到它收到服务端的确认包。 - 在
SYN-SENT状态下,收到了服务端的确认包。客户端将发送服务端FIN报文的确认包,,同时进入ESTABLISHED状态。表明自己准备好发送数据。
对于服务端而言:
- 初始状态同样是
CLOSED状态。 - 在执行bind,listen之后,进入
LISTEN状态。等待客户端的连接。 - 收到客户端的SYN报文以后,会回复确认并发送自己的SYN报文,之后会进入
SYN-RCVD状态等待确认。 - 收到客户端的确认报文以后,进入
ESTABLISHED状态,这时双方就可以互相发送数据了。

