Linux内核在收到非法TCP报文或应用层异常终止连接时主动发送RST报文,典型场景包括:1. 向无监听端口发SYN;2. 收到不属于任何现有连接的报文;3. close()后仍有数据到达;4. shutdown后进程强制退出;5. SO_LINGER设为0时调用close()。

什么情况下Linux会主动发送TCP RST报文
Linux内核在收到不符合当前连接状态的TCP报文,或应用层显式关闭/异常终止连接时,会立即回复RST(Reset)报文。这不是错误,而是TCP协议规定的“拒绝”机制——用于快速终止无效、错乱或不允许的连接尝试。
常见触发RST的5类典型场景
1. 向已关闭的端口发SYN:目标端口无监听进程(如服务未启动),内核直接回RST+ACK,替代“无响应”。这是最常被误认为“防火墙拦截”的现象。
2. 收到不属于任何现有连接的报文:比如序列号严重越界(Seq远超接收窗口)、携带非法标志组合(如SYN+FIN)、或目的IP:Port对应连接已完全关闭(TIME_WAIT结束后又来数据)。
3. 应用层调用close()后仍有数据到达:若一方已close()且对方还在发数据,内核在确认该连接确实无socket绑定后,对新到的数据包回RST。
4. 应用调用shutdown(SHUT_RDWR)后强制退出:进程崩溃或exit前未正确处理socket,残留半开连接,后续报文可能触发RST。
5. SO_LINGER设为0时调用close():跳过四次挥手,直接发送RST终止连接,适用于需要快速释放资源的场景(如负载均衡器后端健康检查失败时)。
用tcpdump抓包定位RST来源的实操要点
先过滤出RST报文:tcpdump -i any 'tcp[tcpflags] & (tcp-rst) != 0';再结合方向、端口、时间戳交叉比对:
- 看RST是否带ACK:带ACK说明是针对某个具体报文的响应(如对方发了乱序包);不带ACK多为服务端拒连(如端口未监听)
- 查RST源IP和端口:若来自本机,说明是本机内核或本地应用发出;若来自对端,需排查对方行为
- 关联前后报文:RST前是否有重传、零窗通告、异常FIN或大量重复ACK?这些可能是连接已断但应用未感知的线索
- 对比netstat/ss输出:执行ss -tn state established '( dport = :8080 )'确认目标端口是否真有ESTABLISHED连接
一个真实排查案例:HTTP服务偶发连接被拒
现象:客户端curl访问Nginx偶尔返回“Connection reset by peer”。抓包发现客户端SYN后,服务端立刻回SYN+ACK+RST(即RST+ACK)。进一步检查:
- netstat显示80端口确有nginx监听,且连接数远低于限制
- 用ss -s发现“orphaned”连接数异常高(>500)
- 查内核参数:net.ipv4.tcp_max_orphans为256,超出后内核强制重置新建连接
- 根因:上游代理未正确关闭长连接,导致Nginx产生大量孤儿连接;调整tcp_max_orphans并优化keepalive timeout后问题消失










