文章目录
-
- 前言
- 一、先搞懂基础:TCP到底是个啥?为啥要握手和挥手?
-
- [1.1 互联网上的数据传输,本质就是"寄快递"](#1.1 互联网上的数据传输,本质就是“寄快递”)
- [1.2 TCP vs UDP:靠谱快递员 vs 扔传单的大爷](#1.2 TCP vs UDP:靠谱快递员 vs 扔传单的大爷)
- [1.3 握手和挥手,就是TCP"靠谱"的核心规矩](#1.3 握手和挥手,就是TCP“靠谱”的核心规矩)
- 二、三次握手:别再死背步骤了!搞懂它到底在"握"什么
-
- [2.1 用一个日常场景,秒懂三次握手全流程](#2.1 用一个日常场景,秒懂三次握手全流程)
- [2.2 拆解每一步:技术细节到底是什么?](#2.2 拆解每一步:技术细节到底是什么?)
-
- [2.2.1 第一次握手:客户端的"探路信号"](#2.2.1 第一次握手:客户端的“探路信号”)
- [2.2.2 第二次握手:服务端的"双向确认"](#2.2.2 第二次握手:服务端的“双向确认”)
- [2.2.3 第三次握手:客户端的"最终确认"](#2.2.3 第三次握手:客户端的“最终确认”)
- [2.3 灵魂拷问:为啥必须是三次?两次不行吗?四次多余吗?](#2.3 灵魂拷问:为啥必须是三次?两次不行吗?四次多余吗?)
-
- [2.3.1 两次握手的致命bug:资源被无限浪费](#2.3.1 两次握手的致命bug:资源被无限浪费)
- [2.3.2 四次握手:完全没必要,纯属画蛇添足](#2.3.2 四次握手:完全没必要,纯属画蛇添足)
- [2.4 面试必问:如果某一次握手的包丢了,会发生什么?](#2.4 面试必问:如果某一次握手的包丢了,会发生什么?)
-
- [2.4.1 第一次握手的SYN包丢了](#2.4.1 第一次握手的SYN包丢了)
- [2.4.2 第二次握手的SYN+ACK包丢了](#2.4.2 第二次握手的SYN+ACK包丢了)
- [2.4.3 第三次握手的ACK包丢了](#2.4.3 第三次握手的ACK包丢了)
- [2.5 线上高频坑:SYN洪水攻击,到底是怎么回事?怎么防?](#2.5 线上高频坑:SYN洪水攻击,到底是怎么回事?怎么防?)
- 三、四次挥手:为啥比握手多一次?搞懂它到底在"挥"什么
-
- [3.1 还是那个日常场景,秒懂四次挥手全流程](#3.1 还是那个日常场景,秒懂四次挥手全流程)
- [3.2 拆解每一步:技术细节到底是什么?](#3.2 拆解每一步:技术细节到底是什么?)
-
- [3.2.1 第一次挥手:主动方的"结束申请"](#3.2.1 第一次挥手:主动方的“结束申请”)
- [3.2.2 第二次挥手:被动方的"收到确认"](#3.2.2 第二次挥手:被动方的“收到确认”)
- [3.2.3 第三次挥手:被动方的"结束申请"](#3.2.3 第三次挥手:被动方的“结束申请”)
- [3.2.4 第四次挥手:主动方的"最终确认"](#3.2.4 第四次挥手:主动方的“最终确认”)
- [3.3 灵魂拷问:为啥握手三次,挥手必须四次?](#3.3 灵魂拷问:为啥握手三次,挥手必须四次?)
- [3.4 面试重灾区:TIME_WAIT状态,到底是干嘛的?](#3.4 面试重灾区:TIME_WAIT状态,到底是干嘛的?)
-
- [3.4.1 为啥要有TIME_WAIT?直接断开不行吗?](#3.4.1 为啥要有TIME_WAIT?直接断开不行吗?)
- [3.4.2 为啥要等2MSL?这个时间是怎么来的?](#3.4.2 为啥要等2MSL?这个时间是怎么来的?)
- [3.4.3 线上出现大量TIME_WAIT,端口耗尽怎么办?](#3.4.3 线上出现大量TIME_WAIT,端口耗尽怎么办?)
- [3.5 面试必问:如果某一次挥手的包丢了,会发生什么?](#3.5 面试必问:如果某一次挥手的包丢了,会发生什么?)
-
- [3.5.1 第一次挥手的FIN包丢了](#3.5.1 第一次挥手的FIN包丢了)
- [3.5.2 第二次挥手的ACK包丢了](#3.5.2 第二次挥手的ACK包丢了)
- [3.5.3 第三次挥手的FIN包丢了](#3.5.3 第三次挥手的FIN包丢了)
- [3.5.4 第四次挥手的ACK包丢了](#3.5.4 第四次挥手的ACK包丢了)
- 四、别再当八股背了!这些高频面试坑,90%的人都踩过
-
- [4.1 面试题1:TCP三次握手过程中,服务端什么时候进入ESTABLISHED状态?](#4.1 面试题1:TCP三次握手过程中,服务端什么时候进入ESTABLISHED状态?)
- [4.2 面试题2:TCP四次挥手,主动断开的一方会进入什么状态?被动方呢?](#4.2 面试题2:TCP四次挥手,主动断开的一方会进入什么状态?被动方呢?)
- [4.3 面试题3:已经建立了TCP连接,客户端突然宕机了,服务端会怎么样?](#4.3 面试题3:已经建立了TCP连接,客户端突然宕机了,服务端会怎么样?)
- [4.4 面试题4:TCP和UDP的区别,除了面向连接,还有这些你不知道的点](#4.4 面试题4:TCP和UDP的区别,除了面向连接,还有这些你不知道的点)
- [4.5 面试题5:什么是半连接队列?什么是全连接队列?满了会怎么样?](#4.5 面试题5:什么是半连接队列?什么是全连接队列?满了会怎么样?)
- 五、2026年了,AI都能写代码了,学这个还有用吗?
P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。
前言
兄弟们,先问个扎心的问题:你是不是背了无数遍三次握手、四次挥手的八股文,面试的时候面试官一问"为啥是三次不是两次",你就支支吾吾答不上来?线上服务出了网络超时、端口耗尽、并发上不去的问题,你抓包看了半天,连SYN、FIN、ACK这些包是啥意思都搞不明白,最后只能靠搜索引擎瞎改配置?
我干了22年开发,从最早的拨号上网,到现在的AI大模型、云原生、万级并发的分布式系统,见过太多线上大事故,追根溯源,就是开发人员连TCP这个最基础的协议都没搞懂,只背了面试题,没懂背后的本质。
2026年了,很多人说,现在AI都能自动生成网络代码、自动配置服务了,还学这些底层东西干嘛?我告诉你,大错特错!AI能帮你写代码,但是不能帮你背锅!线上出了问题,老板不会找AI,只会找你!你要是连三次握手四次挥手都搞不懂,别说涨薪晋升,连保住饭碗都难!
就像去年我带的一个实习生,小伙子用AI一天写了100个接口,上线没半天,服务直接崩了。排查了半天,就是因为他写的短连接请求没处理好TIME_WAIT,导致服务器端口直接耗尽,正常用户根本连不上。你说,这种问题,AI能提前给你预判吗?能给你精准定位根因吗?最后还得靠懂底层原理的人来解决。
这篇文章,我不用那些晦涩难懂的术语,不用密密麻麻的RFC文档,就用大家天天都在接触的生活场景,给你把三次握手、四次挥手讲得明明白白。别说你是高中生,就算你是刚接触电脑的小白,看完也能彻底搞懂,面试再也不怕被问,线上出问题也能一眼定位根因。
一、先搞懂基础:TCP到底是个啥?为啥要握手和挥手?
在讲握手挥手之前,咱得先搞明白,TCP到底是个什么东西,它为啥要搞这么多"繁文缛节"。很多人学了半天,连TCP是干嘛的都没说清楚,这不就是本末倒置了吗?
1.1 互联网上的数据传输,本质就是"寄快递"
咱先抛开所有技术术语,想一个最朴素的问题:你用微信给朋友发一条消息,用浏览器打开一个网页,和AI大模型聊天问问题,这些操作背后,数据到底是怎么从你的手机/电脑,跑到对方的设备上的?
其实很简单,互联网上的所有数据传输,本质上和你寄快递一模一样。你要发的消息、看的图片、刷的视频,都会被拆成一个个小小的"数据包",就像一个个快递包裹,上面写着寄件人地址(你的IP)、收件人地址(对方的IP),然后通过互联网这个"全球快递网络",一站一站传到对方手里。
但是这里有个致命的问题:互联网这个快递网络,是完全不可靠的。你的包裹可能在路上丢了,可能绕了一大圈晚到了,可能同一个包裹发了好几遍,甚至可能包裹到了,但是里面的东西碎了、乱了。
就像你给朋友寄一箱水果,快递路上丢了一半,或者晚了半个月才到,水果都烂了,这肯定不行。那怎么办?我们需要一个"靠谱的快递管家",来保证包裹能完整、有序、不丢不重地送到对方手里,这个管家,就是TCP。
1.2 TCP vs UDP:靠谱快递员 vs 扔传单的大爷
说到TCP,就不得不提它的"亲兄弟"UDP,很多人刚入门就被这俩搞懵,其实用一句话就能分清楚:
TCP是全程给你确认、丢了就重发、包裹按顺序给你排好的靠谱快递员;而UDP是把传单往你小区门口一扔,管你看没看到、捡没捡到的大爷。
UDP的特点就是快,不管你收没收到,我只管发,所以它适合直播、游戏这种对实时性要求高、丢一两个包不影响的场景。比如你打游戏,卡了一下,总不能让游戏把刚才丢的包重发过来,那你早就被人打死了。
但是TCP不一样,它的核心使命就是可靠传输。你发的每一个数据包,对方必须给我回复"收到了",要是没收到,我就重发,直到对方收到为止;而且包裹必须按顺序给你排好,先发的先到,后发的后到,乱了就重新整理。
而我们今天要讲的三次握手,就是TCP这个靠谱管家,和对方建立"可靠传输通道"的过程;四次挥手,就是这个通道用完了,双方和平分手、关闭通道的过程。
1.3 握手和挥手,就是TCP"靠谱"的核心规矩
很多人问,不就是传个数据吗?为啥还要先握手、再挥手,这么麻烦?
我给你举个例子:你要给客户传一份100G的绝密合同文件,你总不能上来就直接发吧?你不得先确认一下:
- 对方的地址是对的,人确实在电脑前,能收到文件
- 对方也确认,你的地址是对的,你确实要发文件
- 双方都确认,自己的发件和收件功能都是正常的
要是没有这个确认过程,你文件发了半天,对方根本没在线,或者地址错了,文件全丢了,这不白忙活了?更严重的,你发的文件被黑客截胡了,你都不知道。
而三次握手,就是干这个确认的事。它要确保客户端和服务端双方,都确认自己和对方的发送、接收能力都是正常的,然后才正式建立连接,开始传数据。
那四次挥手呢?就像你和客户传完文件了,你不能直接把网线拔了就走啊。你得确认:
- 你这边没有要发的数据了
- 对方那边也没有要发的数据了
- 双方都确认,所有数据都传完了,可以断开连接了
要是没有这个过程,你这边说不传了,直接断开了,结果对方还有最后一份重要文件没给你发过来,这不就丢数据了吗?四次挥手,就是保证双方都能"和平分手",不会出现数据丢包、资源浪费的问题。
二、三次握手:别再死背步骤了!搞懂它到底在"握"什么
很多人学三次握手,上来就背"客户端发SYN,服务端回SYN+ACK,客户端再回ACK",背得滚瓜烂熟,但是一问本质,直接懵了。今天咱就先抛开这些字母,用一个你天天都在经历的场景,把三次握手彻底讲透。
2.1 用一个日常场景,秒懂三次握手全流程
2026年了,大家应该都用过AI智能客服吧?不管是查快递、办业务,还是咨询问题,都会先和AI客服对话。我们就用这个场景,完美还原三次握手的全过程:
你现在要找某电商平台的AI客服,咨询你买的商品什么时候发货。整个对话的开头,就是三次握手:
第一次握手 :你对着客服对话框,发了一句:"喂?能听到我说话吗?我要找你咨询订单问题!"
------ 这一步,就是客户端向服务端发送SYN包,核心目的是:我要和你建立连接,你能不能收到我的消息?
第二次握手 :AI客服立刻给你回了一句:"我能听到你说话!你能听到我说话吗?"
------ 这一步,就是服务端向客户端回SYN+ACK包,核心目的有两个:一是告诉你,我收到你的消息了,你的发送能力、我的接收能力都正常;二是反问你,能不能收到我的消息,确认我的发送能力、你的接收能力正常。
第三次握手 :你看到客服的回复,又回了一句:"我也能听到你说话!没问题了,咱们开始聊吧!"
------ 这一步,就是客户端向服务端回ACK包,核心目的是:我收到你的消息了,确认你的发送能力、我的接收能力都正常,双方都没问题,可以正式开始传数据了。
就这三步,就是所谓的三次握手。是不是瞬间就懂了?根本不是什么晦涩的技术,就是两个人打电话,先互相确认能不能听到对方说话,然后再开始聊天。
2.2 拆解每一步:技术细节到底是什么?
刚才用通俗的场景讲完了流程,咱再把对应的技术细节补上,保证你既懂本质,又能应对面试。先给大家补两个最基础的缩写,别再看着字母懵了:
- SYN:同步序列编号,你就理解成"我要建立连接"的请求信号
- ACK:确认编号,你就理解成"我收到你的消息了"的确认信号
2.2.1 第一次握手:客户端的"探路信号"
- 客户端状态变化:CLOSED → SYN_SENT
- 客户端做的事:随机生成一个初始序列号ISN©,把SYN标志位设为1,然后把这个包发给服务端,告诉服务端:我要和你建立连接,这是我的初始序列号,后面我发的数据都会从这个序列号开始递增。
- 核心目的:验证服务端的接收能力是否正常,以及客户端到服务端的网络通路是否正常。
2.2.2 第二次握手:服务端的"双向确认"
- 服务端状态变化:LISTEN → SYN_RCVD
- 服务端做的事:收到客户端的SYN包后,首先要回一个ACK确认包,确认号是ISN©+1,告诉客户端:我收到你的SYN包了;同时,自己也随机生成一个初始序列号ISN(s),把SYN标志位设为1,一起发给客户端,告诉客户端:我也要和你建立连接,这是我的初始序列号。
- 核心目的:一是确认客户端的发送能力、自己的接收能力正常;二是验证自己的发送能力、客户端的接收能力正常。
2.2.3 第三次握手:客户端的"最终确认"
- 客户端状态变化:SYN_SENT → ESTABLISHED
- 服务端状态变化:SYN_RCVD → ESTABLISHED
- 客户端做的事:收到服务端的SYN+ACK包后,回一个ACK确认包,确认号是ISN(s)+1,告诉服务端:我收到你的SYN包了,双方都没问题,可以正式建立连接了。
- 核心目的:最终确认双方的发送、接收能力都完全正常,连接正式建立,开始传输数据。
到这里,三次握手完成,TCP连接正式建立,客户端和服务端就可以开始正常传数据了。
2.3 灵魂拷问:为啥必须是三次?两次不行吗?四次多余吗?
这绝对是面试最高频的问题,没有之一。90%的人背了半天步骤,这个问题都答不明白。今天咱就给你讲得透透的,面试再也不怕被问。
2.3.1 两次握手的致命bug:资源被无限浪费
很多人说,第一次握手客户端发了SYN,第二次握手服务端回了SYN+ACK,这不就双方都确认了吗?为啥还要第三次?
我给你举个生活中的例子,你瞬间就懂了:
你半年前给朋友发了一条微信:"周末约饭吗?",结果当时网络卡了,这条消息没发出去,就卡在了网络里。结果半年后,这条消息突然被发到了朋友的手机上。朋友看到了,立刻给你回了一句:"好啊!周末在哪吃?",然后就推掉了所有周末的安排,等着你约他。
但是你呢?你早就忘了半年前发过这条消息,也根本没打算约他吃饭,所以你看到这条回复,根本不会理他。结果朋友就一直傻等,周末过完了都没等到你的消息,白白浪费了两天的时间。
这就是两次握手的致命问题:失效的连接请求报文,会导致服务端资源被无限浪费。
放到TCP场景里就是:客户端之前发了一个SYN连接请求,卡在了网络里,过了很久才到达服务端。如果是两次握手,服务端收到这个SYN包,就会立刻回SYN+ACK包,然后建立连接,一直等着客户端发数据。但是客户端根本没打算建立这个连接,也不会发数据,服务端就会一直维持这个连接,占用服务器的内存和端口资源。
2026年的今天,电商大促、直播带货的时候,服务器每秒要处理几十万的连接请求,如果是两次握手,黑客只要疯狂发这种失效的SYN包,服务器就会建立无数个无效连接,很快就会把资源耗尽,正常用户根本连不上,直接宕机。
而三次握手就完美解决了这个问题:服务端收到失效的SYN包,回了SYN+ACK之后,客户端不会回第三次的ACK包,服务端就知道这个连接是无效的,不会建立连接,也就不会浪费资源了。
2.3.2 四次握手:完全没必要,纯属画蛇添足
那为啥不能是四次呢?很简单,因为第二次握手的时候,服务端的SYN(我要建立连接)和ACK(我收到你的请求了),完全可以放在一个包里一起发,没必要分成两次。要是分成两次,反而多了一次网络请求,增加了延迟,纯属画蛇添足。
所以,三次握手是保证双方双向确认、同时兼顾效率和安全的最优解,少一次不行,多一次没必要。
2.4 面试必问:如果某一次握手的包丢了,会发生什么?
面试官最喜欢这么问,因为死背八股的人,根本答不上来这种场景题。今天咱就把三种情况都讲清楚:
2.4.1 第一次握手的SYN包丢了
客户端发了SYN包,但是没到服务端。这时候客户端收不到服务端的SYN+ACK包,会触发超时重传机制,重新发SYN包,直到收到服务端的回复,或者达到最大重传次数,直接断开连接。服务端全程无感,不会有任何操作。
2.4.2 第二次握手的SYN+ACK包丢了
服务端收到了客户端的SYN包,回了SYN+ACK包,但是没到客户端。这时候,客户端收不到回复,会超时重传SYN包;而服务端收不到客户端的第三次ACK包,也会超时重传SYN+ACK包,直到收到客户端的ACK,或者达到最大重传次数,断开连接。
2.4.3 第三次握手的ACK包丢了
客户端发了ACK包,但是没到服务端。这时候,客户端已经收到了服务端的SYN+ACK包,会直接进入ESTABLISHED状态,认为连接已经建立,开始发数据。但是服务端没收到ACK包,还处于SYN_RCVD状态,认为连接没建立。
这时候怎么办?TCP的机制很聪明:客户端发的数据包里,会带着ACK确认信息。如果服务端收到了客户端发来的数据包,就算没收到第三次的ACK包,也会确认连接已经建立,直接进入ESTABLISHED状态,开始正常处理数据。只有当服务端一直没收到客户端的数据包,才会超时重传SYN+ACK包,直到达到最大次数,断开连接。
2.5 线上高频坑:SYN洪水攻击,到底是怎么回事?怎么防?
刚才我们提到了SYN洪水攻击,这是线上最常见的网络攻击之一,也是面试常问的点。今天咱就给大家讲明白:
SYN洪水攻击的本质,就是利用三次握手的机制,攻击者伪造大量的虚假IP地址,疯狂给服务端发第一次握手的SYN包。服务端收到之后,会回SYN+ACK包,但是因为IP是虚假的,永远不会收到第三次的ACK包。
这时候,服务端就会维持大量的SYN_RCVD状态的半连接,占满服务器的半连接队列,同时不停重传SYN+ACK包,消耗服务器的CPU和内存资源。等到服务器的资源被耗尽,正常用户的SYN包就进不来了,根本无法建立连接,服务就相当于瘫痪了。
那怎么防护呢?常见的方法有这几种:
- 调大半连接队列的长度,让服务器能承受更多的半连接
- 开启SYN Cookie机制,不分配资源,只记录Cookie信息,只有收到第三次ACK包,验证Cookie合法,才分配资源建立连接
- 缩短SYN超时重传的时间,让无效的半连接更快释放
- 在防火墙层面,限制单个IP的SYN包频率,拦截异常流量
三、四次挥手:为啥比握手多一次?搞懂它到底在"挥"什么
讲完了三次握手,咱再来讲四次挥手。很多人又懵了:为啥建立连接只要三次,断开连接要四次?是不是搞反了?别急,咱还是先用通俗的场景,把四次挥手讲透。
3.1 还是那个日常场景,秒懂四次挥手全流程
还是刚才你和AI客服聊天的场景,你咨询完了订单问题,所有问题都解决了,要结束对话了,这个过程,就是四次挥手:
第一次挥手 :你给客服发了一句:"我的问题都解决了,我没啥要说的了,准备结束对话了哈。"
------ 这一步,就是主动断开方发送FIN包,核心目的是:我这边没有要发的数据了,请求断开连接。
第二次挥手 :客服立刻给你回了一句:"好的,我知道你要结束对话了,我这边还有最后一个订单截图要发给你,发完我就结束。"
------ 这一步,就是被动断开方回ACK包,核心目的是:我收到你的断开请求了,但是我还有数据没发完,你先等我发完。
第三次挥手 :客服把订单截图发给你之后,又发了一句:"我这边的东西都发完了,我也没啥要说的了,准备结束对话了。"
------ 这一步,就是被动断开方发送FIN包,核心目的是:我这边也没有要发的数据了,同意断开连接。
第四次挥手 :你收到之后,回了一句:"好的,我知道了,那咱们结束对话吧!"
------ 这一步,就是主动断开方回ACK包,核心目的是:我收到你的断开请求了,双方都没有数据要发了,可以正式断开连接了。
就这四步,就是四次挥手。是不是瞬间就懂了?根本不是什么复杂的东西,就是两个人挂电话,要互相确认双方都没话说了,才能挂,不能你说挂就直接挂了,万一对方还有话要说呢?
3.2 拆解每一步:技术细节到底是什么?
同样,咱把对应的技术细节补上,先补一个缩写:
- FIN:结束标志位,你就理解成"我没有数据要发了,请求断开连接"的信号
TCP连接是全双工的,也就是说,客户端和服务端都可以同时向对方发数据,所以断开连接的时候,必须双方都确认自己没有数据要发了,才能断开。这也是四次挥手的核心逻辑。
3.2.1 第一次挥手:主动方的"结束申请"
- 主动方状态变化:ESTABLISHED → FIN_WAIT_1
- 主动方做的事:向被动方发送FIN包,告诉被动方:我这边没有要发送的数据了,请求关闭从主动方到被动方的这个方向的连接。
- 核心目的:通知被动方,自己不再发送数据了。
3.2.2 第二次挥手:被动方的"收到确认"
- 被动方状态变化:ESTABLISHED → CLOSE_WAIT
- 主动方状态变化:FIN_WAIT_1 → FIN_WAIT_2
- 被动方做的事:收到FIN包后,立刻回一个ACK包,告诉主动方:我收到你的断开请求了。
- 核心目的:确认收到主动方的FIN包,但是这时候,被动方可能还有数据没发完,所以不能立刻发FIN包,只能先回ACK,继续发剩下的数据。
3.2.3 第三次挥手:被动方的"结束申请"
- 被动方状态变化:CLOSE_WAIT → LAST_ACK
- 被动方做的事:等所有数据都发完之后,向主动方发送FIN包,告诉主动方:我这边也没有要发送的数据了,请求关闭从被动方到主动方的这个方向的连接。
- 核心目的:通知主动方,自己也不再发送数据了,同意断开连接。
3.2.4 第四次挥手:主动方的"最终确认"
- 主动方状态变化:FIN_WAIT_2 → TIME_WAIT
- 被动方状态变化:LAST_ACK → CLOSED
- 主动方做的事:收到FIN包后,立刻回一个ACK包,告诉被动方:我收到你的断开请求了,双方都可以断开了。
- 核心目的:最终确认双方都没有数据要发了,连接正式关闭。被动方收到这个ACK包之后,就会直接进入CLOSED状态,关闭连接。
3.3 灵魂拷问:为啥握手三次,挥手必须四次?
这又是面试高频题,很多人都答不明白。其实核心原因,就一句话:握手的时候,服务端的SYN和ACK可以一起发;但是挥手的时候,被动方的ACK和FIN不能一起发,必须分开。
为啥?因为三次握手的时候,服务端收到客户端的SYN包之后,自己没有数据要处理,直接就可以回SYN+ACK包,两个信号放在一个包里,一步到位。
但是四次挥手不一样,主动方发FIN包过来,只是说主动方没有数据要发了,但是被动方可能还有数据没发完!比如你说要挂电话了,但是客服还有最后一个订单截图要发给你,不能立刻就挂。所以被动方只能先回ACK,告诉你"我知道你要挂了",然后把剩下的数据发完,等数据都发完了,才能再发FIN包,告诉你"我这边也完事了,可以挂了"。
这就是为啥挥手要四次,而不是三次。如果硬要把ACK和FIN放在一起发,就会导致被动方还有数据没发完,连接就断开了,造成数据丢包。
3.4 面试重灾区:TIME_WAIT状态,到底是干嘛的?
TIME_WAIT绝对是TCP协议里,面试问的最多、大家最懵的一个状态。很多人搞不懂,为啥主动断开方发完第四次的ACK包之后,不能直接进入CLOSED状态,非要等2MSL的时间,进入TIME_WAIT状态?
3.4.1 为啥要有TIME_WAIT?直接断开不行吗?
我还是给你举个生活中的例子:你和客服说要结束对话,客服说"我也完事了,可以结束了",你回了一句"好的,结束吧",然后直接就把对话框删了,拉黑了。
但是你怎么知道,客服收到你最后这句话了?如果这句话在路上丢了,客服没收到,它就会一直给你重发"我也完事了,可以结束了"这句话,但是你已经把对话框删了,根本收不到,客服就会一直重发,永远无法正常关闭对话。
TIME_WAIT的第一个核心作用,就是保证被动方能正常关闭连接。如果主动方发完第四次的ACK包之后,直接断开了,而这个ACK包丢了,被动方收不到,就会超时重传第三次的FIN包。这时候主动方已经关闭了,就不会回ACK包,被动方就永远无法正常进入CLOSED状态。
而有了TIME_WAIT状态,主动方会等一段时间,如果收到了被动方重传的FIN包,就会重新回ACK包,并且重置等待时间,保证被动方能收到ACK,正常关闭连接。
第二个核心作用,就是防止"失效的报文"出现在新的连接里。如果没有TIME_WAIT,主动方断开连接之后,立刻用同样的端口和IP,和服务端建立一个新的连接。这时候,之前那个连接里,卡在网络里的数据包,突然到了服务端,服务端就会把这个旧的数据包,当成新连接里的数据包,导致数据混乱,出现严重的bug。
而TIME_WAIT的时间,足够让旧连接里的所有数据包,都在网络里过期消失,不会出现在新的连接里,保证了数据的正确性。
3.4.2 为啥要等2MSL?这个时间是怎么来的?
MSL,全称是Maximum Segment Lifetime,翻译过来就是"报文最大生存时间",也就是一个数据包在网络里,最长能存活多久,超过这个时间,数据包就会被直接丢弃。RFC标准里建议的MSL是2分钟,但是实际系统里,一般是30秒、1分钟或者2分钟。
那为啥是2MSL?很简单:一个数据包,从主动方发到被动方,最长需要1MSL;被动方的重传包,从被动方发到主动方,最长也需要1MSL。加起来就是2MSL。
也就是说,2MSL的时间,足够让主动方发的最后一个ACK包到达被动方,也足够让被动方没收到ACK时,重传的FIN包到达主动方。超过这个时间,要么双方都正常关闭了,要么所有的数据包都过期了,不会有任何影响了。
3.4.3 线上出现大量TIME_WAIT,端口耗尽怎么办?
这是线上最常见的问题之一,尤其是短连接场景,比如爬虫、频繁的API调用,会导致服务器出现大量的TIME_WAIT状态的连接,占满了服务器的端口,导致新的连接无法建立,服务直接崩了。
那怎么解决呢?常见的方法有这几种:
- 尽量使用长连接,代替短连接,减少连接的建立和断开次数,从根源上减少TIME_WAIT
- 调整系统内核参数,开启tcp_tw_reuse,允许将TIME_WAIT状态的端口,重新用于新的TCP连接
- 调整tcp_timestamps参数,配合tcp_tw_reuse使用,保证安全性
- 缩短tcp_fin_timeout的时间,让TIME_WAIT状态更快释放
这里要提醒大家,调整内核参数一定要谨慎,要根据自己的业务场景测试,不要盲目复制网上的配置,不然可能会出现更严重的问题。
3.5 面试必问:如果某一次挥手的包丢了,会发生什么?
和三次握手一样,面试官也喜欢问四次挥手丢包的场景,咱也给大家讲清楚:
3.5.1 第一次挥手的FIN包丢了
主动方发了FIN包,但是没到被动方。这时候主动方收不到被动方的ACK包,会触发超时重传,重新发FIN包,直到收到ACK,或者达到最大重传次数,断开连接。被动方全程无感,不会有任何操作。
3.5.2 第二次挥手的ACK包丢了
被动方回了ACK包,但是没到主动方。这时候主动方收不到ACK,会超时重传FIN包。被动方收到重传的FIN包,会重新回ACK包,直到主动方收到。
3.5.3 第三次挥手的FIN包丢了
被动方发了FIN包,但是没到主动方。这时候被动方收不到主动方的ACK包,会超时重传FIN包。而主动方在FIN_WAIT_2状态,有超时时间,如果超过时间还没收到被动方的FIN包,就会直接断开连接。
3.5.4 第四次挥手的ACK包丢了
主动方回了ACK包,但是没到被动方。这时候被动方收不到ACK,会超时重传FIN包。主动方处于TIME_WAIT状态,收到重传的FIN包,会重新回ACK包,并且重置TIME_WAIT的时间。被动方收到ACK之后,就会正常关闭连接。如果主动方的TIME_WAIT时间到了,被动方还没收到ACK,被动方会继续重传,直到达到最大次数,断开连接。
四、别再当八股背了!这些高频面试坑,90%的人都踩过
讲完了核心原理,咱再给大家整理几个面试最高频的坑,90%的人都踩过,看完这部分,面试直接碾压面试官。
4.1 面试题1:TCP三次握手过程中,服务端什么时候进入ESTABLISHED状态?
很多人会答错,以为是第二次握手之后,其实不是。服务端是在收到第三次握手的ACK包之后,才会进入ESTABLISHED状态。而客户端是在发送完第三次握手的ACK包之后,就进入ESTABLISHED状态了。
4.2 面试题2:TCP四次挥手,主动断开的一方会进入什么状态?被动方呢?
主动断开的一方,会依次进入FIN_WAIT_1、FIN_WAIT_2、TIME_WAIT状态,最后进入CLOSED状态;被动断开的一方,会依次进入CLOSE_WAIT、LAST_ACK状态,最后进入CLOSED状态。
4.3 面试题3:已经建立了TCP连接,客户端突然宕机了,服务端会怎么样?
如果客户端突然宕机,没有给服务端发FIN包,服务端是不会知道客户端宕机了的,会一直维持这个连接,占用资源。这就是TCP的保活机制(KeepAlive)要解决的问题:服务端会每隔一段时间,给客户端发一个保活探测包,如果多次都没收到回复,就会认为客户端已经断开了,主动关闭连接,释放资源。
4.4 面试题4:TCP和UDP的区别,除了面向连接,还有这些你不知道的点
很多人只会答"TCP面向连接,UDP无连接;TCP可靠,UDP不可靠",其实还有这些核心区别,答出来面试官直接对你刮目相看:
- TCP是面向字节流的,会把数据当成一串无结构的字节流,没有边界;UDP是面向报文的,一次发一个完整的报文,有明确的边界
- TCP有拥塞控制、流量控制机制,会根据网络情况调整发送速率;UDP没有,不管网络拥塞不拥塞,都按固定速率发
- TCP是一对一的全双工连接,一个连接只能有两个端点;UDP支持一对一、一对多、多对多的通信
- TCP的头部开销最小20字节,最大60字节;UDP的头部开销只有8字节,非常小
4.5 面试题5:什么是半连接队列?什么是全连接队列?满了会怎么样?
半连接队列(SYN队列):服务端收到客户端的SYN包之后,会把这个连接放到半连接队列里,直到收到第三次的ACK包,才会把连接从半连接队列里拿出来。
全连接队列(Accept队列):服务端收到第三次的ACK包,连接建立完成,会把这个连接放到全连接队列里,等待应用程序调用accept函数取走。
如果半连接队列满了,新来的SYN包会被直接丢弃,无法建立连接;如果全连接队列满了,就算三次握手完成了,连接也会被丢弃,甚至会触发服务端重置连接,导致客户端出现连接超时的问题。
五、2026年了,AI都能写代码了,学这个还有用吗?
最后,我想和兄弟们聊几句心里话。2026年了,AI技术发展得太快了,很多人说,现在AI都能自动生成网络代码,自动处理TCP连接,自动优化服务配置,学这些底层的东西,还有什么用?
我干了22年开发,见过太多技术浪潮,从最早的PC互联网,到移动互联网,再到现在的AI大模型时代。我可以很负责任的告诉你:不管技术怎么变,底层原理永远不会变。AI能帮你写代码,但是不能帮你理解原理,更不能帮你解决线上的疑难杂症。
现在很多程序员,天天用AI写CRUD接口,写业务代码,但是连最基础的TCP协议都不懂,连HTTP请求的底层是什么都不知道。线上出了问题,AI给的答案千篇一律,你自己没有判断能力,根本不知道哪个是对的,哪个是错的,最后只能瞎改配置,越改越乱。
就像去年,我一个朋友的公司,电商大促的时候,服务突然崩了,所有开发都围着电脑看,AI给了十几个解决方案,试了半天都没用。最后我过去,看了一眼服务器的状态,发现是大量的TIME_WAIT占满了端口,两分钟就改了个配置,服务就恢复了。你说,这种问题,AI能给你精准解决吗?能,但是前提是,你自己得懂原理,知道AI给的答案哪个是对的,哪个是错的。
2026年的今天,大厂招聘,AI相关经验已经成了必填项,但是底层基础,更是核心中的核心。你会用AI写代码,别人也会,这根本不是你的核心竞争力。但是你懂底层原理,能解决别人解决不了的问题,能排查别人排查不出来的bug,这才是你能在这个行业站稳脚跟,涨薪晋升的根本。
就像我常说的,AI只是工具,就像程序员手里的IDE,你用的再熟练,不懂代码的底层逻辑,也只是个打字员。只有把底层原理吃透了,你才能真正驾驭AI,而不是被AI淘汰。
P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。