TCP 三次握手四次挥手:我画了六张图,终于讲清楚了
一、先搞清楚:TCP 连接是什么?
很多人把TCP连接想得很玄乎,其实它的本质很实在:通信双方在内核里各自维护了一组状态和缓冲区。所谓建立连接,说白了,就是双方就“我能收到你、你能收到我”这件事,达成一个可靠的共识。
免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
这个过程,全靠数据包头部那几个关键标志位来驱动:
SYN —— 我想建立连接
ACK —— 我确认收到了你的包
FIN —— 我要关闭连接了
RST —— 直接重置,出问题了
理解了这几个信号,接下来的握手和挥手,就全是逻辑推演了。
二、三次握手:不是仪式,是必要条件
先看完整的流程图解,有个全局印象:

具体来说,这三步是这样的:
第一次握手:客户端主动出击,发送一个SYN包,核心意思是“我想建连接,我的初始序号是x”。发完这个包,客户端自己就进入SYN_SENT状态,开始等待回应。
第二次握手:服务端收到SYN后,如果同意连接,就回一个SYN-ACK包。这个包有两层含义:一是确认客户端的SYN(ACK),二是也发出自己的连接请求(SYN),并带上自己的初始序号y。此时,服务端进入SYN_RCVD状态。
第三次握手:客户端收到服务端的SYN-ACK后,发出最后一个ACK包进行确认。这个ACK包送达后,双方才共同进入ESTABLISHED状态,连接至此正式建立,可以开始传输数据了。
三、灵魂拷问:为什么不能两次握手?
这是面试官最爱追问的问题,也是理解TCP设计精髓的关键。光背“防止已失效的连接请求”不够,得看场景。
想象一个网络延迟极高的场景:客户端发了一个连接请求(SYN),但迟迟没收到回复,于是超时重发了一个新的。那个旧的SYN包其实没丢,只是在网络里“迷路”了。如果TCP设计成两次握手——即服务端收到SYN后,回一个SYN-ACK就直接建立连接——那么当那个“迷路”的旧SYN包很久之后终于到达服务端时,服务端会认为这是一个新的连接请求,直接建立连接并分配资源。
但问题是,客户端那边早就放弃这个旧请求了。结果就是,服务端会一直空等,白白消耗着连接资源。这就是著名的“已失效连接请求”问题。
所以,第三次握手那个ACK至关重要。它让服务端能够确认:“刚才发SYN的那个客户端,确实还在线,并且确实收到了我的回复,真想建立这个连接。”没有这第三次确认,服务端就无法区分当前收到的是一个正常的连接请求,还是一个迟到的、早已失效的旧请求。
四、序列号 seq 是什么?

握手过程中交换的序列号(seq)是干嘛的?它主要有两大使命:保证数据有序和检测重复包。
你可能会问,为什么不从0开始,非要弄个随机数作为初始序列号(ISN)?这同样是为了应对网络中的“历史遗留问题”。如果每次连接都从0开始序号,那么上一条连接残留在网络中的、序号重叠的“迷路包”,就可能被新连接错误地接收,导致数据混乱。使用随机化的ISN,可以极大降低这种新旧数据包序号冲突的概率,确保连接的独立性。
五、四次挥手:断开连接为什么比建立还麻烦?

断开连接需要四次交互,比建立连接多一步。原因其实很直接:TCP连接是全双工的。
建立连接时,双方的目标一致,都是开启通信通道,所以客户端的SYN和服务端的SYN-ACK可以“合并”在一次回复里。
但关闭连接时,情况不同了。“我不再发送数据了”和“我也不再发送数据了”是两个独立的、可能不同步的事件。当客户端发送FIN表示要关闭自己这一侧的发送通道时,服务端可能还有数据没传完。所以,服务端必须先回一个ACK,确认收到了客户端的关闭请求,然后继续发送剩余数据。等所有数据都发送完毕后,服务端再发送自己的FIN,关闭自己这一侧的发送通道。正因为ACK和FIN不能像握手时那样同时发出,所以挥手过程自然就变成了四步。
六、TIME_WAIT 是什么?为什么等 2MSL?
这里是面试的加分项,也是实际运维中经常遇到的“坑”。主动关闭连接的一方(比如客户端,或者主动关闭连接的服务器),在发出最后一个ACK之后,并不会立即进入CLOSED状态,而是会进入一个TIME_WAIT状态,并等待2MSL的时间。

MSL(Maximum Segment Lifetime)指报文在网络中的最大存活时间,Linux下通常默认是60秒。等待2MSL,主要出于两个目的:
1. 确保最后一个ACK能到达对端:如果这个ACK丢失了,被动关闭方(服务端)会重发FIN。等待2MSL给了足够时间让这个重传的FIN到达,客户端可以再次回应ACK,从而保证连接能可靠关闭。 2. 让旧连接的报文彻底消散:等待2MSL时间,足以让这个连接产生的所有报文都在网络中消失,避免它们干扰后续新建的、可能复用相同四元组(源IP、源端口、目的IP、目的端口)的新连接。
生产环境的影响:对于高并发短连接的服务,如果服务器是主动关闭方,就会产生大量处于TIME_WAIT状态的连接,占用大量端口,可能导致新连接因无法绑定端口而失败。常见的解决方案是启用端口复用:
在代码层面,可以设置SO_REUSEADDR套接字选项:
// 服务端启动时设置 SO_REUSEADDR,允许复用 TIME_WAIT 状态的端口
int opt = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
或者在系统层面进行配置:
# 允许 TIME_WAIT 状态的 socket 复用
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
七、完整状态机:TCP 连接一生经历的所有状态

这张状态转换图值得仔细琢磨。图中清晰地展示了客户端(蓝色路径)和服务端(绿色路径)在连接生命周期中经历的不同状态。两条路径在ESTABLISHED汇合,共享数据传输的时光,又在关闭时于不同的步骤分道扬镳。理解这张图,TCP连接的生命周期就在你脑子里了。
八、用代码验证:亲眼看到状态变化
理论懂了,最好动手验证一下。用几个简单的命令就能观察TCP状态的变化:
# 终端1:启动一个简单的服务端
nc -l 8080
# 终端2:持续查看连接状态(使用ss命令更现代)
ss -tn state established
# 或者使用传统的netstat
# netstat -an | grep 8080
# 终端3:模拟客户端连接
nc 127.0.0.1 8080
# 此时在终端2,能看到 ESTABLISHED 状态的连接
# 在终端3按 Ctrl+C 断开连接后,再观察终端2,能短暂看到 TIME_WAIT 状态
如果想在程序中获取连接状态,可以使用getsockopt:
// 用 getsockopt 获取 TCP 连接信息
struct tcp_info info;
socklen_t len = sizeof(info);
getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, &len);
// info.tcpi_state 就是当前连接状态(数字对应 TCP_ESTABLISHED=1 等)
printf("TCP state: %d\n", info.tcpi_state);
九、高频面试题精析
Q:三次握手中,第三次 ACK 丢失会怎样?
服务端会一直处于SYN_RCVD状态。它会按照TCP的重传机制,多次重传SYN-ACK包(默认最多5次,间隔时间指数级增长)。如果此时客户端已经进入ESTABLISHED并开始发送数据,那么服务端收到数据包后,会“被动”地进入ESTABLISHED状态。如果始终没收到任何确认或数据,服务端最终会超时关闭这个半连接。
Q:为什么四次挥手不能合并成三次?
根本原因在于,服务端收到FIN时,可能还有数据要发送,所以ACK和FIN不能同时发出。但如果服务端在收到FIN时,恰好没有数据要发送了,那么它完全可以将ACK和自己的FIN合并成一个包发送,这就变成了“三次挥手”。Linux的延迟确认(Delayed ACK)机制有时就会促成这种合并。
Q:SYN Flood攻击是怎么利用握手过程的?
攻击者疯狂发送SYN包,但不回复服务端回应的SYN-ACK,导致服务端维护的半连接队列(SYN_RCVD状态)被占满,无法处理正常的连接请求。防御方法之一是开启SYN Cookie:服务端收到SYN后,不立即分配资源,而是生成一个特殊的序列号(Cookie)放在SYN-ACK中;只有收到携带正确Cookie的ACK时,才正式分配资源建立连接。
Q:close()和shutdown()触发挥手有什么区别?
close()减少文件描述符的引用计数,只有当计数归零时,才会触发TCP的关闭流程(发送FIN)。如果这个套接字被dup()复制过,调用一次close()并不会真正关闭连接。shutdown(fd, SHUT_WR)则不同,它会立即触发TCP的关闭流程,向对端发送FIN,而不管引用计数是多少。因此,想要可靠地、立即地发起四次挥手,应该使用shutdown()。
十、一图总结:三次握手 vs 四次挥手

十一、结语
说到底,TCP三次握手和四次挥手的每一步设计,都蕴含着对网络不可靠性的深刻理解和严谨应对:
- 三次握手,是在最小交互次数下,确保双向通信通道的可靠建立。
- 四次挥手,是由于全双工通信的特性,两个方向的关闭需要独立确认。
- TIME_WAIT状态,则是为了最后一个ACK的可靠交付,以及让旧连接的“幽灵”报文彻底消失,为新连接扫清道路。
把这些逻辑理清楚,下次再面对面试官,你就不再是背诵课本答案,而是可以清晰地画出状态图,讲出每一步背后的“为什么”。这才是真正掌握了TCP连接的核心。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
国内物联网常用的平台有哪些?
物联网平台全景解析:连接万物的核心引擎 在万物互联的时代,物联网平台扮演着怎样的角色?简单来说,它就是那个将海量设备、数据与应用无缝串联起来的“中枢神经系统”。无论是工业生产线上的传感器,还是智能家居里的一个小开关,都需要通过这样一个平台来实现高效的连接、管理与监控。今天,我们就来深入聊聊市面上几个
深入 mmap:被严重低估的 Linux 黑科技,MySQL/Redis/Nginx 都在用它
Mmap 不是什么神秘的黑科技,它的本质是:用虚拟内存的页表映射,替代数据拷贝。 先来思考一个简单的问题。 当你打开浏览器浏览一个网页时,数据从服务器传输到你的屏幕,中间经历了多少次“复制”? 或者,当你用 MySQL 查询一条数据时,从磁盘读取到返回结果,数据又被搬运了几次? 答案可能会让很多人感
MySQL 函数索引避坑指南:别让函数毁了你的索引!
MySQL函数索引:解决“索引列被函数操作后失效”的利器 你是否遇到过这样的场景:明明给字段建了索引,可查询时只要加个简单的函数操作——比如用DATE(create_time)提取日期,或者用UPPER(name)转换大小写——执行速度就瞬间变慢?用EXPLAIN一看,key字段显示为NULL,索引
探索工业物联网IIoT在远程监控和控制中的潜力
工业物联网:远程监控与控制如何重塑产业运营 工业物联网(IIoT)正在全球范围内掀起一场静默的革命。它通过无处不在的连接和数据驱动的洞察,让运营变得更智能、更高效。而在众多引人注目的应用中,远程监控与控制无疑是最具变革性的一个——它让企业几乎能从世界的任何角落,实时地监督和管理自己的核心业务。 这种
Android安全攻防战:如何识破调试者的"隐身术"?
应用安全攻防战:五大调试检测技术实战解析 想象一下,你投入半年心血开发的支付应用,上线仅一周,核心支付逻辑就被攻破。那种感觉,无异于精心设计的保险柜被人用一根牙签撬开。在应用安全这场没有硝烟的战争中,调试检测技术扮演的正是那个“隐形保镖”的角色,专门防范那些试图窥探代码逻辑的“数字间谍”。 这本质上
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

