news 2026/6/1 19:38:34

聊一聊TCP:三次握手我背了100遍,TIME_WAIT还是把我问住了

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
聊一聊TCP:三次握手我背了100遍,TIME_WAIT还是把我问住了

一、为什么今天还要聊TCP?

说实话,TCP这东西,我面试前背过无数遍。三次握手、四次挥手、流量控制、拥塞控制……背得滚瓜烂熟。但真到线上出问题时才发现:背过不代表懂过

比如有一次,我们服务突然出现大量端口分配失败,查了半天发现是TIME_WAIT状态太多了。还有一次,客户端说“请求超时”,抓包一看,超时重传RTO重传一直在发生。

所以今天我决定把这些年踩过的TCP坑,和自己重新理解过的特性,好好捋一遍。不写得太教科书,尽量讲清楚“为什么”。


二、先看一眼TCP长什么样

TCP的报文头其实不算复杂,但有几个字段你最好记住,因为后面大部分特性都靠它们:

  • 序列号(Seq):解决乱序和重复的问题。每个字节都有自己的编号。

  • 确认号(Ack):告诉对方“我收到几号之前的所有数据了”。

  • 窗口大小(Window):告诉对方“我还能收多少,你慢点”。

  • 标志位:SYN用来建立连接,ACK用来确认,FIN用来关闭连接,RST用来强行重置。

你可以把TCP想象成一个带签收和编号的快递系统——IP层只管扔包裹,TCP负责拼顺序、补丢件。


三、三次握手:不只是背个“SYN、SYN+ACK、ACK”

握手的目的很简单:让双方都确认彼此的收发能力是正常的

过程我就不重复默写了,但我想聊聊两个被问烂的问题:

为什么是三次,不是两次?

如果只有两次握手,服务端发了SYN+ACK就认为连接建立了,但万一这个SYN是很久之前延迟到达的旧包呢?客户端早就忘记它了。这时候服务端会白白等一个不存在的连接。

三次握手可以保证:客户端确认了自己的ACK能被服务端收到,历史连接不会意外建立。这是防止历史连接初始化的核心目的。

SYN洪水攻击是怎么回事?

攻击者只发SYN,不回复ACK。服务端每收到一个SYN就分配资源等待,很快把半连接队列塞满。

常规解法是SYN Cookie——不提前分配资源,而是根据这个SYN算出一个cookie,放在SYN+ACK里,只有收到正确的ACK才真正建立连接。


四、四次挥手:TIME_WAIT是个好人

挥手比握手复杂一点,因为TCP是全双工的:双方都要单独关闭自己的方向

客户端发FIN,表示“我不再发数据了”,但还可以收。
服务端回ACK,然后发自己的FIN。
客户端最后回ACK。

这里有一个经常被低估的状态:TIME_WAIT。

TIME_WAIT为什么要等2MSL?

MSL是报文最大生存时间。

两个原因:

  1. 保证最后一个ACK能被服务端收到。如果ACK丢了,服务端会重发FIN,客户端还能再回应。

  2. 让旧连接残留的包在网络上消失,不会干扰新连接。


五、可靠传输:丢包了怎么办?

TCP的可靠性不是靠玄学,是靠确认 + 重传

累积确认

发送方不需要等每一个包的回复,可以连续发一个窗口。接收方回复Ack=100,就表示“99号及之前全收到了”。这叫累积确认

重传策略

超时重传(RTO):发出去一个包,计时器到了还没收到ACK,就重传。但RTO不能固定,因为网络延迟在变。TCP会动态测量RTT,然后计算RTO。

这个机制的问题:如果网络只是轻微丢包,你要等一个RTO(通常几百毫秒),太慢了。

于是有了快速重传:当发送方连续收到3个相同的Ack(比如三个Ack=100),就说明100号包丢了,立即重传,不等超时。

再后来,又有了SACK,它解决了“我不知道到底丢了哪几个”的问题——可以在ACK里明确告诉对方“我缺了100到200之间的某些段”。


六、流量控制:你慢点,我快接不住了

流量控制解决的是接收方能力不足的问题。

接收方把自己的剩余缓冲区大小放在Window字段里告诉发送方。发送方严格遵守这个窗口,不能多发。

如果窗口变成0呢?发送方会定期发零窗口探测去探测窗口有没有打开,防止死锁。

还有一个经典问题:糊涂窗口综合征。如果接收方每次只打开很小的窗口,发送方就只发很少的数据,效率极低。常见的解法是Nagle算法——把小包攒一下再发,但注意在实时性要求高的场景(比如游戏)可能需要TCP_NODELAY。


七、拥塞控制:大家都慢点,前面真的堵了

流量控制是对端的问题,拥塞控制是整个网络的问题。

TCP假设:丢包 = 网络拥塞

核心是四个算法:

  1. 慢启动:刚开始不知道网络容量,从一个小窗口开始,指数增长,直到遇到丢包或达到慢启动阈值。

  2. 拥塞避免:进入这个阶段后,线性增长,小心试探。

  3. 快速重传 + 快速恢复:发生快速重传后,不回到慢启动,而是把窗口减半,继续拥塞避免。

这个模型在当年是合理的,但在高带宽低延迟的网络里,等丢包再降速其实已经晚了。

所以谷歌提出了BBR算法,不再是“丢包驱动”,而是测量实际带宽和RTT来主动调速。现在很多内核已经默认支持了。


八、几个你一定会遇到的坑(实战向)

1. CLOSE_WAIT 堆积

CLOSE_WAIT出现在被动关闭方。如果它收到FIN后不回FIN,就会卡在这个状态。绝大多数情况是代码忘了关socket

2. 粘包问题

TCP是流式协议,没有边界。你发了两个独立的包,接收方可能一次读完。

解法不靠TCP,靠应用层:固定长度、特殊分隔符、或者TLV类型-长度-值格式。

3. 如何快速看连接状态

netstat -an | grep TIME_WAIT | wc -l
ss -state time-wait

后者更快。


九、总结一句人话

TCP的核心哲学很简单:牺牲一点实时性,换来极高的可靠性

靠连接的建立与关闭、确认与重传、流量控制、拥塞控制这四个轮子,跑起了整个互联网的可靠传输。

当然它也有缺点——比如队头阻塞问题,所以现在像QUIC这样的协议(基于UDP实现TCP的可靠性)正在变得流行。

但对每一个后端开发者来说,TCP依然是绕不开的一课。懂它,不是为了背面试题,而是为了在线上出问题时,抓包能看出门道。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/1 19:36:03

从零开始:PPTist免费在线PPT编辑器的完整实战指南

从零开始:PPTist免费在线PPT编辑器的完整实战指南 【免费下载链接】PPTist PowerPoint-ist(/pauəpɔintist/), An online presentation application that replicates most of the commonly used features of MS PowerPoint, allowing for th…

作者头像 李华
网站建设 2026/6/1 19:34:27

3步解决抖音内容采集难题:你的自动化下载工作流指南

3步解决抖音内容采集难题:你的自动化下载工作流指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support…

作者头像 李华
网站建设 2026/6/1 19:27:56

我找到的国内直连 GPT 5.5 / Claude Opus 低成本方案

实测一个月,花费不到一杯奶茶钱。模型原汁原味,不降级,不限速。 先说结论:我为什么折腾了一圈,最终回到 GPT 5.5 之前我写过一篇用 DeepSeek V4 接入 VSCode 的教程。DeepSeek 确实便宜,国内直连也稳&…

作者头像 李华
网站建设 2026/6/1 19:26:50

105.行为识别初步:基于目标检测的简单行为分析

深夜的调试日志:为什么检测框抖成了“鬼影”? 上周三凌晨两点,我在工厂边缘计算盒子上跑一个“人员离岗检测”的demo。YOLOv5s的检测帧率很漂亮,32FPS,但行为判断逻辑却出了邪——明明工人在工位上稍微侧身,系统就连续报“离岗”。盯着监控画面看了十分钟,发现不是检测…

作者头像 李华