三次握手建立连接 · 四次挥手释放连接 · 状态机完整演示
UDP 是无连接的,发了就走,不管对方收没收到。TCP 在发数据之前要先"建立连接",原因有三:
同步序号(ISN):TCP 用序号来标识每个字节,双方各自选择一个初始序号(Initial Sequence Number),必须在握手时告诉对方,否则后续的确认机制无从建立。
协商参数:最大报文段长度(MSS)、窗口大小、是否支持扩展选项(SACK、时间戳等)都在握手时协商。
验证双向可达:只有通过握手,双方才能确认"我能发到你、你能发到我"这条双向通路是通的。这也是为什么需要三次,不是两次。
TCP 首部中有 6 个控制标志位,连接管理主要用到其中三个:
SYN(Synchronize):同步序号,请求建立连接时置 1。携带 SYN 的报文段会消耗一个序号(即使没有数据载荷)。
ACK(Acknowledgment):确认有效位。ACK=1 时确认号字段才有意义。连接建立后,所有报文段的 ACK 都为 1。
FIN(Finish):请求释放连接。与 SYN 一样,FIN 也会消耗一个序号。
注意:SYN=1 的报文段不能携带数据,但要消耗一个序号;FIN=1 的报文段也消耗一个序号。这两点在计算题中非常重要。
客户端主动发起连接,服务器处于监听状态(LISTEN)。三次握手的本质是双方各自告知序号,并且都得到确认。
也可使用键盘 ← → 翻步
三次握手的完整过程:
SYN seq=x。客户端进入 SYN_SENT 状态。ack=x+1),同时发送自己的 SYN(seq=y)。服务器进入 SYN_RCVD 状态。ack=y+1)。第三次握手可以携带数据。双方进入 ESTABLISHED 状态,连接建立。注意 ISN(初始序号)的选择:ISN 并非从 0 开始,而是根据系统时钟选取一个随机值,目的是防止旧连接的延迟报文被误认为新连接的数据。
这是 408 的经典考题。核心原因:两次握手只能让服务器确认客户端能发、服务器能收;但客户端无法确认服务器能发、客户端能收。
更本质的原因是:TCP 是全双工的,双方都需要同步序号,且都需要得到确认。总共需要 4 次(客户端 SYN + 服务器 ACK + 服务器 SYN + 客户端 ACK),但服务器可以把 ACK 和 SYN 合并成一个报文,因此是三次。
如果只有两次握手,还会有一个具体问题:历史失效连接请求。客户端发了一个 SYN,在网络中滞留很久后到达服务器,服务器以为是新连接,发出 SYN+ACK 后就进入 ESTABLISHED,开始等待数据——但客户端早已不再理这个连接了,服务器的资源就白白浪费了。三次握手中,客户端不会回复 ACK,服务器就不会进入 ESTABLISHED。
客户端确认:我能发、能收。
服务器确认:我能发、能收。
双向通路全部验证。
服务器发出 SYN+ACK 后即 ESTABLISHED,但不知道客户端是否收到。历史失效 SYN 会导致资源浪费。
连接释放需要四次,原因是 TCP 是全双工的,两个方向的数据流要分别关闭。主动关闭方(通常是客户端)先关自己到对方的方向,被动关闭方可能还有数据要发,等发完再关另一方向。
也可使用键盘 ← → 翻步
四次挥手的关键细节:
seq=u):表示客户端没有数据要发了,进入 FIN_WAIT_1。CLOSE_WAIT。此时连接处于半关闭状态——客户端不再发数据,但服务器还可以继续发。客户端收到 ACK 后进入 FIN_WAIT_2。seq=v):服务器数据发完,发出自己的 FIN,进入 LAST_ACK。TIME_WAIT,等待 2MSL 后再关闭。服务器收到 ACK 后立即进入 CLOSED。TIME_WAIT 是四次挥手中最容易考到的知识点。客户端发出最后一个 ACK 后,不会立即关闭,而是等待 2MSL(Maximum Segment Lifetime,报文最大生存时间)。
原因有两个:
原因一:确保最后一个 ACK 能到达服务器。如果服务器没有收到最后的 ACK,会重传 FIN。客户端等待 2MSL,意味着能收到这个重传的 FIN 并再次发 ACK。如果客户端立即关闭,则无法处理重传,服务器就会一直处于 LAST_ACK 状态。
原因二:防止"旧连接的残留报文"污染新连接。等待 2MSL 能确保本次连接所有报文都在网络中消失,下一个用同样四元组(源IP/端口+目标IP/端口)建立的连接不会收到旧的迷途报文。
408 常考状态转移,尤其是三次握手和四次挥手各阶段双方的状态。
| 阶段 | 事件 | 客户端状态 | 服务器状态 |
|---|---|---|---|
| 握手前 | — | CLOSED | LISTEN |
| 握手① | 客户端发 SYN | SYN_SENT | LISTEN |
| 握手② | 服务器发 SYN+ACK | SYN_SENT | SYN_RCVD |
| 握手③ | 客户端发 ACK | ESTABLISHED | ESTABLISHED |
| 挥手① | 客户端发 FIN | FIN_WAIT_1 | ESTABLISHED |
| 挥手② | 服务器发 ACK | FIN_WAIT_2 | CLOSE_WAIT |
| 挥手③ | 服务器发 FIN | FIN_WAIT_2 | LAST_ACK |
| 挥手④ | 客户端发 ACK | TIME_WAIT | CLOSED |
| 2MSL后 | 定时器超时 | CLOSED | CLOSED |
易错点:握手③之后服务器才进入 ESTABLISHED(不是②之后);TIME_WAIT 只在主动关闭方(客户端)出现,不在服务器。
三次握手 = 双方各同步一个序号,都得到确认,最少需要三次。两次不够(不能验证双向可达,无法防止历史失效 SYN);更多次没意义。
四次挥手 = 全双工的两条数据流各自独立关闭。②③之间存在半关闭状态,服务器可以继续发数据,这是与握手的本质区别。
TIME_WAIT = 主动关闭方的最后一道保险,等待 2MSL 的目的是确保最后 ACK 送达 + 清空网络中的旧报文。