首页 / 内容指南 / 当前文章

TCP的SYN队列、Accept队列、ESTABLISHED、CLOSE_WAIT、FIN_WAIT和TIME_WAIT有什么区别?

发布于 2026-08-26 · xieyipai.com 编辑部

SYN队列保存尚未完成三次握手的入站连接状态;Accept队列保存已经完成握手、但应用尚未accept()取走的连接;ESTABLISHED表示连接已建立并可传输数据;CLOSE_WAIT表示本机已经收到对端FIN,正在等本地应用关闭;FIN_WAIT_1/2表示本机主动关闭后等待对端确认或FIN;TIME_WAIT表示主动关闭一方在最终确认后保留连接状态,避免旧报文影响新连接并允许重发最后ACK。

本文目录(27 节)

直接答案

SYN队列保存尚未完成三次握手的入站连接状态;Accept队列保存已经完成握手、但应用尚未accept()取走的连接;ESTABLISHED表示连接已建立并可传输数据;CLOSE_WAIT表示本机已经收到对端FIN,正在等本地应用关闭;FIN_WAIT_1/2表示本机主动关闭后等待对端确认或FIN;TIME_WAIT表示主动关闭一方在最终确认后保留连接状态,避免旧报文影响新连接并允许重发最后ACK。

队列满、CLOSE_WAIT堆积和TIME_WAIT很多不是同一种问题。前两者往往分别指向握手/接入能力和应用未关闭Socket;大量TIME_WAIT可能只是短连接负载的正常结果。必须结合方向、进程、四元组、速率和内核计数判断。

一、关键状态与队列对比

↔ 表格可左右滑动查看完整内容
名称所处阶段谁负责推进堆积常见含义
SYN队列三次握手未完成TCP内核握手洪峰、丢包、攻击或队列不足
Accept队列握手完成、未被应用接收应用调用accept()应用接入慢或事件循环阻塞
ESTABLISHED双向连接已建立应用与TCP活跃连接或未及时超时
CLOSE_WAIT对端已关闭发送方向本地应用调用close()应用资源泄漏或处理卡住
FIN_WAIT本地主动关闭对端回应关闭流程对端迟迟不发FIN或网络异常
TIME_WAIT主动关闭后的保护期内核定时器短连接多、主动关闭多

Linux工具显示的队列值与内核版本、Socket类型和命令字段有关,不要把所有Recv-Q都解释成同一队列。

二、三次握手与SYN状态

客户端主动连接时进入SYN-SENT并发送SYN。服务端监听Socket收到SYN后回复SYN-ACK,并为半连接保留状态,表现为SYN-RECEIVED。客户端最后返回ACK,握手完成。

SYN队列主要对应尚未收到最终ACK的半连接。客户端超时可能发生在SYN丢失、SYN-ACK回程丢失、防火墙拦截或队列无法容纳新状态等多个环节。

三、Accept队列保存什么

握手完成后,内核把连接放入等待应用接收的队列。应用调用accept()后才获得一个用于收发数据的新Socket。监听Socket继续负责接收新的连接请求。

因此客户端看到TCP握手成功,不代表服务器业务线程已经处理请求。Accept队列积压时,连接可能已建立,但应用迟迟未接手。

四、listen backlog控制哪个队列

在现代Linux中,listen()的backlog参数限制的是已完成连接等待accept()的队列;未完成握手的SYN队列由单独内核参数控制。Linux listen(2)文档明确区分了两者。

backlog还会受到系统级somaxconn上限约束。应用传入一个很大数字不等于内核实际采用相同容量,应检查运行时有效值和监听Socket统计。

五、SYN队列满会发生什么

在连接突发、SYN洪泛或应用主机资源紧张时,半连接队列可能耗尽。Linux可根据配置采用SYN cookies等机制缓解状态占用,但这不是替代容量规划和攻击防护的万能方案。

先观察SYN接收速率、重传、SYN cookies计数与源地址分布,再决定扩队列、增加实例、调负载均衡或实施防护。只调一个参数可能隐藏真正瓶颈。

六、Accept队列满会发生什么

当应用消费连接速度低于握手完成速度,Accept队列会接近上限。新连接可能延迟、重试或失败,具体表现取决于系统实现和参数。

常见根因包括事件循环阻塞、线程池耗尽、进程暂停、文件描述符不足或应用在accept()后执行过多同步工作。增大队列只能吸收短暂突发,无法修复持续处理能力不足。

七、ESTABLISHED表示什么

RFC 9293把ESTABLISHED定义为开放连接,接收的数据可交付给用户,是正常数据传输阶段。它不表示连接此刻一定有流量,也不表示应用健康。

连接可能长时间空闲但仍为ESTABLISHED。要判断是否泄漏,应结合应用协议空闲超时、最后读写时间、文件描述符和连接对端,而不是只看数量。

八、半关闭与双向独立性

TCP的两个传输方向可以独立关闭。一方发送FIN只表示“我没有更多数据要发送”,仍可以继续接收对方剩余数据。RFC 9293称之为half-closed connection。

应用若把收到EOF直接等同于连接所有方向已失效,可能丢掉尚未发送的响应。正确处理取决于应用协议是否允许半关闭。

九、CLOSE_WAIT是怎么进入的

本机在ESTABLISHED状态收到对端FIN后,确认该FIN并进入CLOSE_WAIT。协议栈正在等待本地应用发起关闭,随后发送自己的FIN进入LAST_ACK。

因此CLOSE_WAIT主要是本地应用责任。内核不能替应用决定何时完成剩余数据处理并关闭Socket。

十、CLOSE_WAIT大量堆积意味着什么

大量长期CLOSE_WAIT常见于代码未在异常路径关闭连接、线程卡住、连接池归还失败或上层库没有释放响应体。对端已经明确关闭,本机应用却仍持有文件描述符。

先按进程和远端聚合,再检查最早出现时间、调用栈与连接创建/关闭指标。重启进程会清掉现象,但不能证明泄漏被修复。

十一、FIN_WAIT_1表示什么

本地应用主动关闭后,TCP发送FIN并进入FIN-WAIT-1,等待对端确认本地FIN,或同时等待对端自己的FIN。收到ACK后通常进入FIN-WAIT-2。

短暂出现属于正常关闭流程。若长期堆积,要检查FIN是否重传、回程ACK是否被丢弃,以及对端或中间设备是否异常。

十二、FIN_WAIT_2表示什么

FIN-WAIT-2表示本地FIN已经被对端确认,但对端还没有发送自己的FIN。本地发送方向已关闭,仍等待远端结束其发送方向。

长时间存在可能是对端应用一直保持半关闭连接,或协议双方对关闭时机理解不一致。内核可能有超时回收机制,但应用仍应定义合理的关闭和空闲策略。

十三、LAST_ACK表示什么

收到对端FIN的一方在应用最终关闭后发送自己的FIN,进入LAST-ACK等待对方确认。ACK到达后连接状态被删除。

大量LAST_ACK可能提示最后ACK回程丢失、对端已异常消失或网络设备丢弃关闭报文。需要抓包判断是FIN持续重传还是本机未发送成功。

十四、TIME_WAIT为何存在

主动关闭一方在最终ACK后进入TIME-WAIT。RFC 9293给出两个核心目的:确保对端能收到终止请求的确认,以及避免旧连接延迟报文影响使用相同四元组的新连接。

如果对端重发FIN,TIME-WAIT端可以再次发送ACK。立即删除状态会让对端无法确认正常关闭。

十五、2MSL是什么意思

标准关闭流程中,TIME-WAIT通常持续两倍最大报文生存时间,即2MSL。具体操作系统使用的时间和实现细节应查当前内核文档。

不要把某台机器观察到的固定秒数当成所有系统和所有网络的协议常量。应用设计应容忍正常TIME-WAIT存在。

十六、TIME_WAIT多是否等于泄漏

不等于。每秒建立大量短连接且本机主动关闭时,TIME_WAIT数量约与连接创建速率和保留时间相关。反向代理、爬虫或API客户端出现较多很常见。

真正风险是耗尽临时端口、连接跟踪表或内存。应看新建速率、目标分布、端口范围、连接复用率和失败计数,而不是机械追求数量为零。

十七、为什么服务端也会有TIME_WAIT

谁先主动发送FIN并完成主动关闭流程,谁通常进入TIME-WAIT,与“客户端/服务端”角色没有必然对应。如果HTTP服务器主动关闭响应连接,服务端完全可能持有大量TIME_WAIT。

先从抓包确认关闭方向,再调整Keep-Alive、连接池或上游超时。只因端口是监听端口就假设客户端主动关闭,会走错排障方向。

十八、RST与FIN关闭有什么区别

FIN表示有序、可确认的正常关闭,已排队数据仍按协议交付;RST表示连接被中止,状态通常快速丢弃,并向应用报告重置。

使用带未读数据的强制关闭或异常进程退出可能产生RST。不要用RST规避TIME_WAIT,这可能造成数据截断和难以诊断的connection reset。

十九、端口耗尽与四元组

TCP连接由源IP、源端口、目标IP、目标端口四元组标识。客户端连接同一目标时,可用临时源端口有限;大量并发或TIME_WAIT可能让新连接难以分配四元组。

连接多个目标时端口复用条件不同。容量评估应按源地址和目标聚合,不能只用全机端口范围除以连接总数。

二十、连接池如何减少压力

HTTP持久连接和数据库连接池复用已建立连接,可降低握手、端口和TIME_WAIT压力。但连接池过大或缺少空闲回收也会制造大量ESTABLISHED和服务端资源占用。

配置应匹配并发、请求时长、上游容量与故障恢复需求。复用不是把连接永久保持,而是受控地减少重复创建。

二十一、如何查看Linux连接状态

可使用ss按状态、进程、端口和计时器查看Socket,结合/proc/net、内核SNMP统计和应用指标。监听Socket的队列字段与已连接Socket的收发队列含义不同。

采样时保存时间序列。单次快照无法区分稳定存量、瞬时峰值和持续增长,尤其无法判断CLOSE_WAIT是否真正泄漏。

二十二、推荐排障顺序

第一,确认错误发生在连接前、握手中还是已建立后。第二,按本地端口、远端、进程和状态聚合。第三,查看队列与内核丢弃计数。第四,抓取小范围报文确认SYN、ACK、FIN和RST方向。第五,对照应用连接生命周期和超时。

最后才调整内核参数。没有证据就扩大队列或缩短状态超时,可能把可见告警变成静默丢包。

二十三、常见误区

误区包括:把SYN队列和Accept队列视为同一个backlog;把所有TIME_WAIT都当泄漏;用内核参数清理CLOSE_WAIT;只看服务端不看主动关闭方向;以及把TCP已建立等同于HTTP服务健康。

正确问题不是“哪个状态最多”,而是“哪个状态的停留时间和进入速率偏离业务预期”。

常见问题

1. CLOSE_WAIT能通过调低TIME_WAIT解决吗?

不能。CLOSE_WAIT在等待本地应用关闭,TIME_WAIT是另一条正常关闭路径。应修复应用Socket生命周期。

2. backlog越大越好吗?

不是。更大队列只能吸收突发,并消耗资源;若应用持续处理不过来,延迟会增加,最终仍会溢出。

3. ESTABLISHED很多说明服务正常吗?

不一定。它只说明TCP连接处于数据传输状态,应用可能卡死、空闲或协议层超时。

4. 谁会进入TIME_WAIT?

通常是主动关闭并发送最后ACK的一方。客户端和服务端都可能成为主动关闭方。

5. 如何区分SYN队列满和Accept队列满?

结合监听Socket队列、SYN重传、SYN cookies、握手完成率和应用accept()速度判断。抓包可确认客户端停在哪个握手阶段。

结论

SYN队列处理半连接,Accept队列等待应用接入,ESTABLISHED承载正常传输,CLOSE_WAIT等待本地应用关闭,FIN_WAIT等待远端完成关闭,TIME_WAIT保护旧连接终止。按TCP状态机、队列层级和关闭方向取证,比看到数量就调内核参数更可靠。

参考来源

  1. RFC Editor:RFC 9293 Transmission Control Protocol,https://www.rfc-editor.org/info/rfc9293/
  2. Linux man-pages:listen(2),https://man7.org/linux/man-pages/man2/listen.2.html
  3. Linux man-pages:tcp(7),https://man7.org/linux/man-pages/man7/tcp.7.html
  4. Linux man-pages:netstat(8),https://man7.org/linux/man-pages/man8/netstat.8.html