当前位置: 首页 > news >正文

聊一聊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依然是绕不开的一课。懂它,不是为了背面试题,而是为了在线上出问题时,抓包能看出门道。

http://www.jsqmd.com/news/931158/

相关文章:

  • 给资产装上“数字翅膀”:RWA系统开发者的千亿级造富风口
  • 抖音创作者作品批量下载神器:5分钟掌握高效视频采集
  • 成都角钢公司|角钢厂家|角钢批发推荐|四川盛世钢联国际贸易有限公司供应 - 四川盛世钢联营销中心
  • YACReader终极指南:如何打造你的个人漫画图书馆
  • 2026年连锁酒店加盟品牌差异横评:定位层级、物业适配与收益模型全对比 - 科技焦点
  • 青岛修漏水哪家好|2026 青岛靠谱防水补漏、全屋漏水维修分区推荐 - 吉修匠
  • 3PEAK思瑞浦 TPA6031-S5TR SOT23-5 运算放大器
  • 零基础理解 RAG:从文档分块、向量化到相似度检索,带你搞懂检索增强生成的底层核心逻辑
  • OmenSuperHub深度解析:开源硬件控制工具的技术实现与实践指南
  • 科研写作从低效到持续高产,只需要掌握这套Gemini 3.1 Pro的辅助路径
  • 500+网站支持:WebToEpub如何将任意网页小说转换为标准EPUB电子书
  • m4s-converter:轻松解锁B站缓存视频的免费转换神器
  • 2026河南新乡昆虫标本厂家实力排行推荐:合规性与性价比对比 - 奔跑123
  • 成都工字钢公司|工字钢厂家|工字钢现货推荐|四川盛世钢联国际贸易有限公司库存 - 四川盛世钢联营销中心
  • STM32智能温控系统:3步打造你的第一个嵌入式PID控制器
  • 告别死记硬背!用这10个高频ROS2命令玩转你的机器人项目
  • LangGraph 深度拆解:从 Agent Demo 到生产级编排系统
  • 网盘直链下载助手:免费开源工具,3分钟突破六大网盘下载限速
  • 3步解锁网易云音乐格式限制?ncmdump让你真正拥有付费音乐
  • AI文本生成伦理困境:从技术原理到实践挑战的深度解析
  • FFXIV ACT插件内存操作技术解析:实现副本动画跳过的自动化处理
  • 2026年5月钢结构直销厂家性价比高的,优秀的钢结构,二手钢结构拆迁效率高不耽误后续施工 - 品牌推荐师
  • 基于ESP8266与Google Assistant的智能宠物喂食器DIY全攻略
  • 开发者对接大模型 API 太繁琐?CenToken 帮你省 80% 时间
  • Linux Shell 脚本入门、执行方式与批量压解实战
  • MATIEC:将工业自动化语言带入开源世界的编译器
  • Prompt工程实战复盘:从反复改稿到搭建【提示词编写标准化智能体工作流】
  • Sora 2生成长视频崩溃频发?独家披露GPU显存碎片化监控脚本+TensorRT优化配置(实测A100 80G吞吐提升3.2倍)
  • WinUtil:3步快速完成Windows系统优化与软件管理的终极免费方案
  • TV Bro:专为Android电视设计的终极遥控器友好浏览器解决方案