"TCP连接"这四个字,做技术的人几乎每天都在和它打交道。数据库连不上、服务起不来、curl 报 connection reset、Docker 映射端口失败、ESP8266 接平台就掉线——表面看是各种工具在报错,深挖下去,问题全都落在同一个点上:TCP连接。
这篇文章不打算按教科书的方式讲协议。我想把 TCP 连接从头到尾拆开揉碎,从三次握手到底层参数,从一行报错到完整排查思路,把我这些年踩过的坑、常用的命令、值得记住的判断方法都写出来。适合后端开发、运维、网络安全、嵌入式开发、测试,以及所有被"连不上""断连""超时"折磨过的人。
1. 从握手到挥手:TCP连接的生命周期
1.1 三次握手:连接不是"建立"出来的,是"确认"出来的
很多人背过三次握手的流程:客户端发 SYN,服务端回 SYN + ACK,客户端再回 ACK,然后连接建立。但真正理解它为什么要三次,比记住流程更重要。
我习惯用一个类比:凌晨你往楼下超市订货——你打电话喊一句"我订了十箱水,收到了吗",这是第一次确认;超市老板说"收到了,我马上送",这是第二次确认;你再回一句"好,等你",这是第三次确认。只有双方都确认"对方知道我来了、我也知道对方在",这条沟通链路才算真正建立。
TCP 之所以必须三次,核心是为了防止历史重复报文干扰新连接。想象一个场景:客户端第一次发的 SYN 由于网络拥堵滞后了,客户端等不到回应,超时重发了一个新的 SYN,这次顺利建立连接、传完数据、正常断开。结果第一个滞留在网络里的 SYN 此时才到达服务端。如果只有两次握手,服务端收到这个迟到的 SYN 后会直接进入 ESTABLISHED 状态并等待数据,白白浪费资源,还会让对端以为建立了新连接。而三次握手时,旧的 SYN 即使到达,服务端回了 SYN + ACK 后也收不到客户端的 ACK(因为客户端已经在处理新连接了),这个旧连接自然就废掉了。
握手期间还有一个容易被忽略的现象——SYN Flood。客户端只发 SYN 不回应 ACK,服务端就要一直维护半连接队列,直到超时。这也就是为什么大流量攻击下服务经常出现连接建立缓慢、大量 SYN_RECV,后面讲调优时会提到 syncookies。
1.2 四次挥手:断开比建立多一次的真相
断开连接比建立连接多一次,原因其实很简单:TCP 是全双工的,数据能在两个方向独立传输,每一侧都必须单独关闭。
假设客户端主动断开。第一步:客户端发送 FIN,表示"我这边数据发完了",进入 FIN_WAIT_1;第二步:服务端回 ACK,表示"我收到你的关闭请求了",进入 CLOSE_WAIT,但此时服务端如果还有数据要发给客户端,依然可以继续发;第三步:服务端把剩余数据全部发完后,也发送 FIN,进入 LAST_ACK,表示"我这边也完事了";第四步:客户端回 ACK,进入 TIME_WAIT,再等待一段时间后彻底关闭。
这里最容易被搞晕的是为什么主动关闭方要等 2MSL(两倍的报文最大生存时间)。我第一次排故障时也不理解:等就等,干嘛要等那么久?两个原因:一是确保最后一个 ACK 能送到服务端,万一丢了,服务端会重发 FIN,客户端在 TIME_WAIT 内还能再回一次 ACK;二是让这条连接上所有在网络里游荡的报文都自然消亡,避免它们被"套用"到相同 IP 和端口的下一轮连接上。
很多业务代码里的"断连"问题,其实就出在这一步。服务端大量连接处于 CLOSE_WAIT,说明服务端应用程序处理完数据后没有及时调用 close();客户端大量连接处于 TIME_WAIT,说明主动关闭太频繁,端口和内存都被拖住了。这两类状态你在线上用 ss 命令看得清清楚楚,后面单独讲。
1.3 连接状态机:一眼识破连接卡在哪一步
排障的时候,状态就是最直接的"病历单"。我用得最多的命令是 ss -tan,它会把所有 TCP 连接状态打出来,常见的就这么几个:
| 状态 | 含义 | 常见的坑 |
|---|---|---|
| LISTEN | 服务端在监听端口 | 端口被占用、backlog 溢出 |
| SYN_SENT | 客户端发了 SYN,没等到回应 | 防火墙丢包、目标不可达 |
| SYN_RECV | 服务端收到 SYN,回了 SYN+ACK,没等到 ACK | 半连接队列满、恶意流量 |
| ESTABLISHED | 双向连接正常 | 大量堆积说明连接数没回收 |
| FIN_WAIT_2 | 主动关闭方等对端 FIN | 对端不关 socket,可能一直挂着 |
| CLOSE_WAIT | 对端关了,本端还没关 | 程序没调用 close,常见 bug |
| TIME_WAIT | 主动关闭方在等 2MSL | 大量堆积会占端口,调 tw_reuse |
| LAST_ACK | 被动关闭方等最后一个 ACK | 最后一个 ACK 丢了会重发 FIN |
我最近排查过一
