在深入探讨TCP握手挥手机制前,需要明确一个重要概念:HTTP协议本身并不直接实现三次握手和四次挥手,这些机制实际上是其底层传输协议TCP(传输控制协议) 的特性。HTTP作为应用层协议,建立在TCP提供的可靠连接之上。
当你在浏览器中输入网址时,背后发生的连接建立和断开过程就是通过TCP的三次握手和四次挥手完成的。
第一部分:TCP三次握手(建立连接)
核心目标
确保客户端和服务器双方都具备发送和接收数据的能力,并同步初始序列号。
详细过程
第一步:SYN(同步)报文
客户端 → 服务器:SYN=1, seq=x
客户端:主动打开连接,发送SYN报文
SYN标志位:置为1,表示请求建立连接
初始序列号(seq):随机生成一个值x(假设x=100)
状态变化:客户端进入SYN_SENT状态
第二步:SYN-ACK(同步确认)报文
服务器 → 客户端:SYN=1, ACK=1, seq=y, ack=x+1
服务器:收到SYN后,同意建立连接
SYN标志位:置为1,表示同意建立连接
ACK标志位:置为1,确认号有效
初始序列号(seq):随机生成一个值y(假设y=300)
确认号(ack):设置为x+1(即101),表示"已收到序列号x,期待下次收到x+1"
状态变化:服务器进入SYN_RECEIVED状态
第三步:ACK(确认)报文
客户端 → 服务器:ACK=1, seq=x+1, ack=y+1
客户端:确认服务器的SYN-ACK报文
ACK标志位:置为1
序列号(seq):设置为x+1(即101)
确认号(ack):设置为y+1(即301),表示"已收到序列号y,期待下次收到y+1"
可携带数据:此时可以开始发送应用层数据(如HTTP请求)
状态变化:双方都进入ESTABLISHED状态
为什么需要三次而不是两次?
这是一个经典的面试问题!关键在于防止已失效的连接请求报文突然又传送到服务器:
场景模拟(两次握手的问题):
客户端发送SYN请求,但因网络延迟未到达
客户端超时重发SYN,建立连接后正常通信并关闭
此时第一个延迟的SYN终于到达服务器
如果是两次握手:服务器收到后直接进入ESTABLISHED状态,等待客户端数据,但客户端早已关闭连接
结果:服务器资源被无效占用("半连接"问题)
三次握手如何解决:
在第三次握手时,客户端告诉服务器"我知道你同意连接了",这样服务器就能区分出延迟的旧请求。
TCP四次挥手(终止连接)
核心目标:优雅地终止连接,确保双方数据都传输完成。
详细过程
第一次挥手:FIN(结束)报文
客户端 → 服务器:FIN=1, seq=u
发起方:通常是客户端(但任何一方都可以主动关闭)
FIN标志位置为1,表示数据发送完毕,请求关闭连接
序列号(seq):设置为已传输数据最后字节的序列号+1(假设u=500)
状态变化:客户端进入FIN_WAIT_1状态
第二次挥手:ACK(确认)报文
服务器 → 客户端:ACK=1, seq=v, ack=u+1
服务器:确认收到关闭请求
ACK标志位:置为1
确认号(ack):设置为u+1(即501)
注意:此时服务器可能还有数据要发送,连接处于半关闭状态
状态变化:客户端进入FIN_WAIT_2状态,服务器进入CLOSE_WAIT状态
第三次挥手:FIN(结束)报文
服务器 → 客户端:FIN=1, ACK=1, seq=w, ack=u+1
服务器:数据发送完毕后,发送自己的FIN报文
FIN和ACK标志位:同时置为1
序列号(seq):设置为服务器最后发送数据的序列号+1(假设w=800)
确认号(ack):仍为u+1(501)
状态变化:服务器进入LAST_ACK状态
第四次挥手:ACK(确认)报文
客户端 → 服务器:ACK=1, seq=u+1, ack=w+1
客户端:确认服务器的FIN报文
ACK标志位:置为1
确认号(ack):设置为w+1(即801)
等待时间:客户端进入TIME_WAIT状态,等待2MSL(Maximum Segment Lifetime)
最终状态:双方都进入CLOSED状态
为什么需要四次而不是三次?
因为TCP连接是全双工的:
每个方向都需要独立关闭
客户端说"我发完了"(FIN)→ 服务器说"好的"(ACK)
服务器说"我也发完了"(FIN)→ 客户端说"好的"(ACK)
ACK和FIN不能总是合并发送,因为服务器可能还有数据要传送
为什么需要TIME_WAIT状态?
主要目的:确保最后的ACK到达:如果ACK丢失,服务器会重发FIN,客户端需要能响应。让旧报文在网络中消逝:防止相同四元组(源IP、源端口、目标IP、目标端口)的旧连接报文干扰新连接。
。MSL(Maximum Segment Lifetime)
。报文最大生存时间,通常为30秒、1分钟或2分钟
。TIME_WAIT持续时间:2MSL(通常为1-4分钟)
。Linux查看:cat /proc/sys/net/ipv4/tcp_fin_timeout
特殊情况和优化
。同时打开与同时关闭
同时打开:双方同时发送SYN,需要4次报文交换(罕见)
同时关闭:双方同时发送FIN,可以合并步骤
。半关闭状态
一方发送FIN后,仍可以接收数据
使用shutdown()函数实现
。连接重置(RST)
异常情况下的立即终止
发送RST标志位为1的报文
不经过四次挥手,直接释放资源
性能优化考虑
减少握手开销:
TCP Fast Open(TFO):在第一次SYN中携带数据
连接复用:HTTP/1.1的持久连接、HTTP/2的多路复用
TCP_NODELAY/TCP_CORK:控制小包发送策略
调整挥手参数:

HTTP与TCP握手挥手的实际关系
HTTP/1.0 vs HTTP/1.1 vs HTTP/2
。HTTP/1.0:短连接
请求1:握手 → HTTP请求/响应 → 挥手
请求2:握手 → HTTP请求/响应 → 挥手
请求3:握手 → HTTP请求/响应 → 挥手
每个请求都经历完整的TCP连接生命周期
性能极差,已被淘汰
。HTTP/1.1:持久连接(默认)
握手 → HTTP请求/响应 → HTTP请求/响应 → ... → 挥手
Connection: keep-alive 头部
多个HTTP请求复用同一个TCP连接
服务器可设置保持时间:Keep-Alive: timeout=5, max=100
。HTTP/2:多路复用
握手 → 多个并发的HTTP请求/响应流 → 挥手
单一TCP连接上并行处理多个请求
进一步减少握手开销
。HTTP/3:基于QUIC
使用UDP而非TCP
内置TLS,减少握手次数
解决队头阻塞问题
浏览器并发连接限制
同一域名通常限制6-8个TCP连接
因此网站常用CDN、域名分片等技术
附加
。什么建立连接是三次,关闭连接是四次?
建立时:SYN和ACK可以合并(服务器同意连接时立即确认)
关闭时:ACK和FIN经常不能合并,因为服务器可能还有数据要发送
。TIME_WAIT状态太多怎么办?
根本原因:高并发短连接场景
解决方案:
使用连接池
设置合理的tcp_fin_timeout
开启tcp_tw_reuse(客户端)
调整应用架构,减少短连接
。如果握手过程中报文丢失怎么办?
SYN丢失:客户端超时重传(指数退避)
SYN-ACK丢失:服务器超时重传,客户端也会重传SYN
ACK丢失:服务器超时重传SYN-ACK
。SYN Flood攻击是什么?如何防御?
攻击原理:伪造大量SYN报文但不完成握手
防御措施:
SYN Cookie:不分配资源直到完成三次握手
连接速率限制
防火墙过滤
核心要点总结
。三次握手确保双方都能收发数据,防止历史连接问题
。四次挥手优雅终止全双工连接,确保数据完整性
。TIME_WAIT防止报文混淆,保证连接彻底关闭
。HTTP性能优化的关键是减少TCP握手挥手开销
。现代HTTP使用持久连接、HTTP/2多路复用等技术优化