一文讲透TCP三次握手、四次挥手与常见故障

admin 2026-07-12 04:42:58 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文以Linux访问443端口为例,系统讲解TCP三次握手与四次挥手原理,并针对超时、拒绝连接、重置、首字节慢、重传等常见故障提供排查方法。强调将排查顺序固化为名称解析、路由、监听、双端抓包、套接字状态与计数、应用分段,并给出最小证据集与工程建议,帮助读者将网络故障从感觉慢变为可验证的工程问题。 综合评分: 90 文章分类: 实战经验,技术标准,安全运营


cover_image

一文讲透 TCP 三次握手、四次挥手与常见故障

点击关注👉 点击关注👉

马哥Linux运维

2026年7月11日 13:00 广东

在小说阅读器读本章

去阅读

一文讲透 TCP 三次握手、四次挥手与常见故障

TCP 故障不能靠背概念解决。真正有用的是把一次访问拆成名称解析、路由、握手、TLS、应用首字节和关闭,再用抓包、套接字状态、内核计数与应用日志对齐。本文以 Linux 上访问 443 端口为例,IP、端口和路径均需按实际环境替换。

实际场景:超时、拒绝与重置不是一回事

用户访问 API 时,可能看到超时、connection refused 或 connection reset by peer。超时通常意味着 SYN 未到、SYN-ACK 未回,或后续报文被丢;拒绝通常是目标地址用 RST 响应,目标端口没有监听或策略显式拒绝;重置则表示会话被一端主动中断。建连成功后首字节慢,重点往往已经不在 TCP。

先完成最小检查:

bash

getent ahosts api.example.internal
ip route get 10.20.30.40
sudo ss -ltnp '( sport = :443 )'
curl -vk --connect-timeout 5 https://api.example.internal/health

将域名、IP 和 health 路径替换为真实服务。若服务没有无副作用健康接口,不要虚构路径。curl 的 --connect-timeout 只限制建连时间,不限制整个请求。

核心原理:三次握手确认了什么

客户端先发 SYN,携带自己的初始序列号;服务端返回 SYN-ACK,确认客户端序列号并提供自己的初始序列号;客户端最后 ACK。三步的意义是双方确认对方具备收发能力,并同步序列号空间。客户端第一次 SYN 后常处于 SYN-SENT;服务端收到 SYN、发出 SYN-ACK 后为 SYN-RECV;最后 ACK 到达后双方为 ESTABLISHED

text

客户端                         服务端
SYN, seq=x       ----------->
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<----------- SYN-ACK, seq=y, ack=x+1
ACK, ack=y+1 &nbsp; &nbsp; ----------->
双方进入 ESTABLISHED

查看当前状态:

bash

ss -tan state syn-sent
ss -tan state syn-recv
ss -tan state established&nbsp;'( sport = :443 or dport = :443 )'

客户端大量 SYN-SENT 时,检查 DNS 返回地址、出口路由、ACL、安全组和目标监听。服务端大量 SYN-RECV 时,说明服务端收到 SYN 但未完成最后 ACK,需验证回程、客户端策略、SYN flood 与监听队列压力。状态是瞬时快照,不能脱离抓包和连接速率单独下结论。

监听队列还受应用 listen(backlog)、内核 net.core.somaxconnnet.ipv4.tcp_max_syn_backlog 等共同影响,且实现会因内核版本不同而不同。不要只调大一个 sysctl 就宣布优化完成;先确认 accept 延迟、SYN-RECV、应用线程和系统资源是否共同表明队列是瓶颈。

核心原理:四次挥手与 TIME-WAIT

TCP 是全双工协议,两个方向可独立关闭。主动关闭方发 FIN;对端先 ACK,仍可发送剩余数据;对端完成发送后再发 FIN;主动方 ACK 后进入 TIME-WAIT,等待一段时间以处理最后 ACK 丢失和旧报文。

text

主动关闭方 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 被动关闭方
FIN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;----------->
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<----------- ACK
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<----------- FIN
ACK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;----------->
主动方经历 TIME-WAIT 后关闭

ACK 与 FIN 可以合并,所以抓包不一定永远有四个独立包。TIME-WAIT 也不是故障,短连接客户端、反向代理和高并发访问都会产生它:

bash

ss -tan state time-wait&nbsp;'( sport = :443 or dport = :443 )'
ss -s
cat&nbsp;/proc/net/sockstat

TIME-WAIT 多时,先判断它位于客户端还是服务端、连接是否确实短命、客户端是否缺少连接复用、上游是否在异常重试。不要用“清理 TIME-WAIT”、随意缩短内核超时或开启未知 sysctl 来处理。错误调参会影响端口复用和旧报文隔离,制造更难复现的间歇故障。

验证实验:用双端抓包确认握手

在服务端针对一台获授权测试客户端抓取 30 秒:

bash

sudo&nbsp;timeout&nbsp;30 tcpdump -ni any&nbsp;'host 10.20.30.50 and tcp port 443'&nbsp;-nn -tttt -vv

示例输出:

text

2026-07-10 14:00:00.100001 IP 10.20.30.50.52000 > 10.20.30.40.443: Flags [S], seq 1000, win 64240
2026-07-10 14:00:00.100120 IP 10.20.30.40.443 > 10.20.30.50.52000: Flags [S.], seq 2000, ack 1001, win 65160
2026-07-10 14:00:00.100300 IP 10.20.30.50.52000 > 10.20.30.40.443: Flags [.], ack 2001, win 502

完整三包说明服务端观察到握手成功,但不能证明 TLS 和应用正常。服务端反复看到同一个 SYN、没有最后 ACK,优先检查回程;客户端重复发 SYN、服务端没有记录,优先检查客户端出口、负载均衡、ACL 与目标地址;服务端回 RST,再检查监听、四层代理或本机策略。

客户端同步抓包可避免单点观测误导:

bash

sudo&nbsp;timeout&nbsp;30 tcpdump -ni any&nbsp;'host 10.20.30.40 and tcp port 443'&nbsp;-nn -tttt -vv

抓包必须限定主机、端口和时长。报文中可能含地址、协议元数据或未加密载荷,不能长期抓全量生产流量,也不能把未脱敏 pcap 随意传播。

常见故障一:SYN 超时与路径问题

表现通常是 curl 在 connect 阶段超时、客户端有 SYN-SENT 或抓包看到 SYN 重传。检查顺序是:DNS 是否解析到正确地址;路由是否正确;目标安全组与 ACL;服务端监听;服务端是否收到 SYN;服务端回包是否到客户端。

服务端检查监听和内核统计:

bash

sudo&nbsp;ss -ltnp&nbsp;'( sport = :443 )'
netstat -s | grep -Ei&nbsp;'listen|SYN|retrans'
nstat -az | grep -E&nbsp;'TcpExtListen|TcpRetransSegs|TcpTimeouts'

netstatnstat 字段会随内核和 iproute2 版本变化,实际名称以本机输出为准。一个计数器增长不等于本次故障,必须比较同一观察窗口的增量、抓包和流量。接入 Prometheus 时可观察 TCP 重传、监听溢出、连接状态与网卡错误,具体指标名称以实际 exporter 暴露的指标为准。

防火墙修改属于高风险操作,影响范围可能是整个业务端口和管理面。执行前导出现有规则、保留控制台、精确确认源/目的/协议/端口,先对最小网段灰度。先只读查看:

bash

sudo&nbsp;nft list ruleset

不要执行 flush ruleset、停止防火墙服务或直接开放 0.0.0.0/0。备份是保存规则集和配置管理版本;验证是在授权源地址建连并确认管理面未受影响;回滚是恢复已备份规则或声明式配置的上一版本。

常见故障二:拒绝连接与 RST

connection refused 通常是目标地址立即返回 RST。确认服务进程是否在正确地址和端口监听:

bash

sudo&nbsp;ss -ltnp&nbsp;'( sport = :443 )'
sudo&nbsp;lsof -nP -iTCP:443 -sTCP:LISTEN
systemctl status nginx --no-pager

lsof 可能未安装,没有时以 ss 为准。监听在 127.0.0.1:443 的服务不会接受远端连接;0.0.0.0:443 覆盖 IPv4,IPv6 还要检查 [::]:443 和双栈策略。不要为了可达性盲目改成全地址监听,必须评估暴露面、反向代理和防火墙。

已建立后出现 RST 时,观察 RST 的源地址和时序。真实服务端发出 RST 时检查进程重启、应用超时、连接管理或代理;负载均衡地址发出 RST 时检查其空闲超时、后端健康与连接复用;若来自中间安全设备,需要网络团队按五元组和时间窗口提供设备证据。客户端的一句 reset 报错不足以判断责任方。

常见故障三:握手快、首字节慢

握手完成后,TLS、HTTP、后端依赖、磁盘和 CPU 均可能拖慢请求。用 curl 分段,而不是把整个耗时都归给 TCP:

bash

curl -sk -o /dev/null -w&nbsp;'dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} first_byte=%{time_starttransfer} total=%{time_total}\n'&nbsp;https://api.example.internal/health
ss -tin&nbsp;'( dport = :443 or sport = :443 )'

示例输出:

text

dns=0.002 connect=0.004 tls=0.018 first_byte=1.442 total=1.443

示例中 TCP 与 TLS 很快、首字节慢,应转查应用和后端,而不是调 TCP 参数。性能基线必须在相同源、相同 DNS、相同负载窗口多次采样,并用应用请求日志、追踪或后端指标佐证。

常见故障四:重传、窗口与 MTU

重复段、重传或长时间没有 ACK 可能来自丢包、拥塞、网卡错误、队列满、路径 MTU 或接收端处理慢。检查接口和套接字:

bash

ip -s&nbsp;link&nbsp;show dev eth0
ethtool -S eth0
ss -tin&nbsp;'( sport = :443 or dport = :443 )'

将 eth0 替换为真实网卡。ethtool 字段依赖驱动,不能跨机器照搬解释。仅大报文、VPN 或隧道失败时可做不分片探测:

bash

ping -M&nbsp;do&nbsp;-s 1472 10.20.30.40

1472 加 IPv4 的 28 字节头为 1500;IPv6 和隧道应按实际 MTU 调整。ICMP 被限制时该试验无结论,不能据此直接修改 MTU。变更网卡 MTU、路由或内核 TCP 参数会影响主机所有连接:执行前检查依赖服务和现网 MTU,备份网络配置,在单节点灰度,验证双向流量和业务请求,并准备通过控制台恢复原配置。

工程建议

将排查顺序固化为:名称解析、路由、监听、双端抓包、套接字状态与计数、应用分段。根因必须有证据:SYN 是否到达、SYN-ACK 是否返回、ACK 是否完成、RST 或 FIN 来自谁、计数器是否在同一时间窗口变化、TCP 成功后应用是否才变慢。

高连接量服务应优先从工程设计减少不必要短连接:正确配置客户端连接池和 keep-alive,让负载均衡、代理与后端的超时策略一致,建立连接时间、TLS 时间、首字节时间和错误率的分段监控。不要为了消除 TIME-WAIT 或 SYN-RECV 的表象盲调 sysctl。每次涉及防火墙、内核参数、服务重启、负载均衡切换或扩缩容,都要写清影响范围、执行前检查、备份、灰度或 dry-run、验证和回滚。

三次握手、四次挥手不是面试答案,而是一套读懂证据的坐标系。把抓包、ss、内核日志和应用耗时放到同一时间线,网络故障才会从“感觉很慢”变成可验证、可回滚的工程问题。

排障运行手册:从客户端到服务端的最小证据集

网络问题通常跨越多个团队。为了让网络、平台、应用和安全团队能够用同一组事实协作,每次工单建议先附上最小证据集:发生时间(含时区);客户端和服务端的 IP、端口、协议;是否经 DNS、负载均衡、代理、NAT 或 VPN;客户端报错原文;两端抓包的开始时间;服务端监听状态;最近配置或发布变更。不要把“用户访问不通”作为唯一信息,因为它无法定位报文在哪一跳消失。

客户端可按以下顺序执行只读检查:

bash

date&nbsp;-Is
getent ahosts api.example.internal
ip route get 10.20.30.40
ss -tan&nbsp;'( dport = :443 )'
curl -vk --connect-timeout 5 https://api.example.internal/health

服务端则记录:

bash

date&nbsp;-Is
sudo&nbsp;ss -ltnp&nbsp;'( sport = :443 )'
sudo&nbsp;ip addr show
sudo&nbsp;ip route show
sudo&nbsp;journalctl -u nginx --since&nbsp;'15 minutes ago'&nbsp;--no-pager

这里的 nginx 仅是示例服务名,需要替换成实际监听进程对应的 systemd 单元;如果服务不是 systemd 管理,读取其真实日志路径。测试开始前应确认客户端 NAT 后的实际源地址,因为服务端抓包过滤的是可见源 IP,不一定是用户机器的私网地址。

TCP 状态与应用状态为何会相互矛盾

ESTABLISHED 只说明内核认为 TCP 会话已经建立,不代表对端业务线程正在处理请求。一个应用可以 accept 连接后因线程池耗尽、后端连接阻塞、TLS 协商错误或请求体读取等待而没有响应。相反,应用日志出现请求开始也不代表客户端一定收到结果,回程丢包或客户端提前关闭都可能使最终响应不可达。

因此排查必须区分四个时间点:DNS 返回地址;TCP connect 完成;TLS 握手完成;HTTP 首字节或应用协议首响应到达。对于 HTTPS,可以用 curl 的时间字段采样;对于自定义 TCP 协议,可以由客户端记录 connect 成功时间和首个协议响应时间,或使用应用自身的结构化日志。伪代码示例如下,不能直接作为 shell 命令执行:

text

伪代码:
record(t_dns_done)
connect(remote_address, timeout)
record(t_tcp_connected)
perform_protocol_handshake()
record(t_protocol_ready)
send_request(); read_first_response_byte()
record(t_first_byte)

只有当 t_tcp_connected 明显变慢时,才优先检查三次握手路径;t_first_byte - t_protocol_ready 变慢则通常应转交应用或依赖链路。这个区分可以避免给内核参数“背锅”。

连接队列与文件描述符:什么时候值得检查

服务进程虽然监听端口,仍可能因为进程文件描述符耗尽、accept 不及时或应用线程阻塞而表现为连接失败。先获取事实,不要直接增大限制:

bash

pidof nginx
cat&nbsp;/proc/<service_pid>/limits | grep -i&nbsp;'open files'
sudo&nbsp;ls&nbsp;/proc/<service_pid>/fd |&nbsp;wc&nbsp;-l
sudo&nbsp;ss -ltnp&nbsp;'( sport = :443 )'

<service_pid> 必须替换为真实服务进程 PID;前两条需要读取该进程信息的权限。文件描述符数接近限制、同一窗口服务日志出现 too many open files,并且新连接失败,三项证据同时出现时才有理由处理限制或泄漏。单看 fd 数高并不说明错误,因为高并发代理本来就会保有大量连接。

提高 LimitNOFILE、修改 systemd 单元、重启服务或更改 sysctl 均是高风险变更,影响范围包括该服务的重启窗口、连接上限和资源使用。执行前检查现有单元来源、应用支持上限、宿主机内存以及是否有冗余副本;备份当前 unit override 或配置管理版本;先在单副本灰度;验证新连接、旧连接、fd 使用量和错误日志;回滚为恢复原 override 并按变更窗口重启该副本。不要直接编辑 /usr/lib/systemd/system 下的供应商 unit,升级可能覆盖它;应遵循本机的 systemd override 和配置管理规范。

负载均衡与连接超时:一定要对齐层级

经四层或七层负载均衡访问时,至少存在客户端到负载均衡、负载均衡到后端两条 TCP 连接。客户端成功握手只能证明第一段正常;后端 ss 正常也不能证明负载均衡已选择该节点。排查时分别确认 VIP、负载均衡日志、后端健康状态、后端源地址和每一段的超时配置。

超时配置应按层级对齐:客户端连接超时、负载均衡空闲超时、反向代理读写超时、应用请求超时、数据库或下游超时。不存在适用于所有系统的固定秒数;上层超时如果短于正常业务耗时,会主动断开仍在工作的下层请求;下层超时如果明显更短,则可能反复向上游返回重置或 5xx。变更超时前必须从访问日志和追踪中取得分位数与最长合法请求证据,先在小流量后端池或单路由灰度,并确认连接数、内存与排队没有异常放大。

负载均衡切流、后端摘除、扩缩容和主从切换都属于高风险操作。影响范围包含连接中断、会话粘滞失效、缓存预热和数据一致性;执行前需确认健康副本、会话/状态迁移策略和回切条件;备份是保存当前后端池与路由配置;灰度是先切小比例流量或一个可回收节点;验证是连接建立、关键请求、错误率和延迟同时达标;回滚是按已记录的旧配置把流量逐步切回,不能在异常期间反复全量切换。

复盘与预防:让报文证据可用

复盘应记录问题属于握手、数据传输还是关闭阶段;谁发出 SYN、SYN-ACK、ACK、FIN 或 RST;双端抓包与日志的时间差;受影响的地址族、网段与负载均衡路径;最终修复及其验证。对于反复出现的连接问题,建立持续观测而非每次现场抓包:服务监听状态、TCP 重传、网卡错误、连接队列、应用首字节时间、负载均衡后端健康和 DNS 解析失败率都应有明确责任人。

需要强调的是,监控只能提示异常,不能自动替代根因证据。例如 TCP 重传升高可能是路径丢包、服务端 CPU 饱和、网卡异常或接收端应用阻塞;必须回到同一时间窗口的抓包、系统资源和应用日志。把这种证据链固化,才不会在每一次连接故障中重复猜测。

文末阅读福利

仅目前来说,无论是运维人转型提升,还是零基础想转行IT,最好的岗位就是云计算运维&SRE岗位。

为了帮助大家早日快速入门云计算运维领域,给大家整理了一套【最新运维资料】高级运维工程师必备技能资料包(文末一键免费领取),内容有多详实丰富看下图!

1.38张最全工程师技能图谱

2.面试大礼包

3.Linux书籍

内容比较多,就不一一展示了

以上所有资料获取请扫码:

识别上方二维码

备注:2026最新运维资料

100%免费领取

(是扫码领取,不是在公众号后台回复,别看错了哦)


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:马哥Linux运维 点击关注👉 点击关注👉《一文讲透 TCP 三次握手、四次挥手与常见故障》

评论:0   参与:  0