ECONNREFUSED、ECONNRESET、ETIMEDOUT、EHOSTUNREACH、ENETUNREACH 和 EPIPE 有什么区别?
网络程序报错时,Connection refused、Connection reset by peer、Connection timed out、No route to host、Network is unreachable 和 Broken pipe 经常被笼统归为“网络不通”。实际上,它们对应不同失败阶段。ECONNREFUSED 通常表示目标端明确拒绝连接;ECONNRESET 表示已建立或正在处理的连接被强制重置;ETIMEDOUT 表示等待连接或确认超过期限;EHOSTUNREACH、ENETUNREACH 指向路由或可达性问题;EPIPE 表示本地继续向已经关闭写方向的流式连接发送数据。 先定位阶段,再排查服务、路由、防火墙和应用协议,远比反复重启有效。
本文目录(25 节)
核心差异速查
| 错误 | 常见阶段 | 内核观察 | 优先检查 |
|---|---|---|---|
| ECONNREFUSED | connect | 对端或中间设备明确拒绝 | 监听端口、目标地址、防火墙拒绝 |
| ECONNRESET | connect 后或传输中 | 收到 RST 或连接被强制终止 | 对端日志、协议错配、中间代理 |
| ETIMEDOUT | 建连或传输 | 多次等待后仍无有效响应 | 丢包、静默丢弃、路径和超时预算 |
| EHOSTUNREACH | 路由/发送 | 没有匹配主机的有效路径或收到不可达 | 路由、网关、邻居发现、ICMP |
| ENETUNREACH | 路由/发送 | 目标网络不可达 | 本机路由、接口、网络命名空间 |
| EPIPE | 写操作 | 本地写端已关闭或连接已断 | 关闭时序、SIGPIPE、重连策略 |
错误名是内核向应用暴露的结果,不一定能唯一证明某个物理设备有故障。同一根因经过代理、运行时或容器网络后,可能映射成不同异常。
先按失败阶段定位
把一次请求拆成 DNS 解析、路由选择、邻居解析、TCP 建连、TLS 握手、应用请求、响应读取和连接关闭。errno 只能覆盖其中部分层次。例如域名解析失败通常不是这里六个 TCP errno;TLS 证书错误也不是 ECONNREFUSED。
记录异常发生在哪个系统调用、目标 IP 和端口、连接是否曾建立、已经发送或收到多少字节,是正确解释错误的前提。
ECONNREFUSED 表示什么
在 TCP 主动连接中,如果目标对一个 SYN 返回有效 RST,RFC 9293 将该情形描述为连接被拒绝,操作系统通常向应用返回 ECONNREFUSED。常见原因是目标 IP 可到达,但端口没有监听服务,或防火墙采用 reject 而非静默 drop。
“被拒绝”比超时提供了更明确的反馈,但不等于目标应用一定主动执行了拒绝;主机防火墙、负载均衡器或其他中间设备也可能生成拒绝响应。
ECONNREFUSED 的排查顺序
先确认程序使用的最终 IP、端口和地址族,再到服务端检查进程是否监听正确接口。只监听 127.0.0.1 的服务无法通过外部地址访问,只监听 IPv6 也不必然接受 IPv4。
然后核对容器端口映射、负载均衡后端、服务发现结果与安全策略。若某些节点成功、某些节点拒绝,应按解析结果和后端实例分组,而不是只测域名一次。
ETIMEDOUT 表示什么
ETIMEDOUT 表示内核或应用等待的操作超过相应期限。在建连阶段,常见表现是 SYN 重传后仍未收到 SYN-ACK 或明确拒绝;在已连接阶段,Linux TCP 文档说明,重传数据长期未被确认时也可能报告 ETIMEDOUT。
超时只证明规定时间内没有得到所需结果,不能单凭它断言“服务器宕机”。静默防火墙、回程路由错误、严重丢包、对端拥塞或本地超时设置过短都可能造成相同表象。
refused 与 timeout 的关键区别
refused 通常意味着路径上返回了明确的负面答复,因此失败较快;timeout 则意味着没有及时得到足以完成或明确终止操作的答复。前者优先查监听与拒绝规则,后者优先查双向路径、丢包与静默丢弃。
但应用框架可能统一包装异常,重试层还可能延迟最终报错。诊断时应同时查看内核错误、抓包时间线和实际重试次数。
ECONNRESET 表示什么
TCP RST 用于强制终止或拒绝与当前连接状态不相符的通信。RFC 9293 规定,在已同步状态收到有效 RST 时,未完成的收发操作应得到 reset 通知,连接状态被清除。Linux send(2) 也将 ECONNRESET 描述为连接被对端重置。
常见场景包括对端进程异常退出、应用主动设置中止式关闭、代理空闲超时、向已复用但实际过期的连接发送请求,以及把非 TLS 数据发往 TLS 端口后被设备终止。
FIN 与 RST 不相同
FIN 表示一端正常结束自己的发送方向,TCP 仍支持半关闭,另一端可继续发送剩余数据。RST 表示异常或立即终止,未完成数据可能被丢弃,应用通常收到 reset 类错误。
看到 “peer” 也不能直接把责任归到业务服务器。四层负载均衡、防火墙、NAT 和反向代理均可能是实际发送 RST 的节点,需要结合抓包中的源地址和设备日志判断。
为什么连接刚建立也会 reset
三次握手成功只证明当时 TCP 端点接受连接,不证明上层协议有效。服务可能在读取首包后发现协议、SNI、认证或请求格式不符合要求,于是立即关闭,部分实现会产生 RST。
连接池中的陈旧连接也很常见:代理已经因空闲策略清理连接,而客户端仍认为可以复用,下一次写入或读取才暴露 reset。
EPIPE 表示什么
POSIX 和 Linux 文档中,EPIPE 表示套接字写方向已关闭,或面向连接的套接字已不再连接。对流式套接字发送时,系统还可能向线程或进程产生 SIGPIPE;使用 MSG_NOSIGNAL 可抑制该信号,但 EPIPE 错误仍应处理。
因此 Broken pipe 主要描述本地写操作所见状态,而不等于网络中真的有一根“管道断了”。它经常是更早发生的远端关闭或超时,在后续写入时才被应用察觉。
ECONNRESET 与 EPIPE 为什么会交替出现
具体返回哪个错误取决于连接状态、先执行 read 还是 write、内核已经处理到哪个报文,以及运行时如何转换系统错误。一次读取可能先得到 ECONNRESET,随后写入得到 EPIPE;另一种时序可能直接在 send 时暴露错误。
不要建立“reset 必定是服务端、broken pipe 必定是客户端”的简单规则。两者都需要还原关闭时序。
SIGPIPE 为什么必须显式考虑
在默认信号处理策略下,写入已关闭的管道或套接字可能触发 SIGPIPE,导致进程终止,看起来像应用无日志崩溃。网络库通常会忽略信号或使用无信号发送选项,再把 EPIPE 交给调用者。
抑制 SIGPIPE 只是让程序有机会处理错误,并没有恢复连接。应用仍应停止继续写入、清理请求状态,并依据幂等性决定是否重连重试。
EHOSTUNREACH 表示什么
Linux ip(7) 说明,EHOSTUNREACH 可在没有匹配目标的有效路由条目时出现,也可能源于远端路由器返回的 ICMP 错误。它表明当前主机无法得到通向该目标主机的有效路径。
在同网段中,邻居解析失败、网关不可达、策略路由错误或容器网络隔离也可能表现为主机不可达。此时只检查应用监听端口通常没有意义。
ENETUNREACH 表示什么
ENETUNREACH 更侧重目标网络没有可用路径,常见于默认路由缺失、网络接口未启用、错误的路由表或网络命名空间没有相应出口。不同操作系统和协议栈对 host 与 network unreachable 的映射细节可能不同。
诊断时不要过度依赖中文错误文本,应保留原始 errno、地址族和路由查询结果,并在发生错误的同一个网络命名空间内检查。
host unreachable 与 network unreachable 怎么分
两者都属于建连前的可达性问题。Network unreachable 通常指连目标所属网络的路线都没有;Host unreachable 则可能已有更广泛的网络路径,但无法到达具体主机或收到主机不可达反馈。
这是诊断方向而非跨平台绝对保证。容器运行时、VPN、策略路由和语言库可能重新包装错误,最终仍应以系统路由和报文证据验证。
DNS 失败不要混入这六类
如果域名没有解析出地址,程序甚至还没有进入对某个目标 IP 的 TCP connect。常见错误是名称不存在、临时解析失败或解析超时,应检查 DNS 响应、搜索域和 resolver 配置。
若域名返回多个 A/AAAA 地址,客户端可能先在一个地址遇到不可达,再回退到另一个成功。日志只记录最终结果会掩盖真实路径,最好记录每次候选地址尝试。
防火墙 reject 与 drop 的差异
reject 会返回明确错误,例如 TCP RST 或适当的 ICMP 不可达,因此客户端常较快收到 refused 或 unreachable。drop 静默丢包,客户端往往只能等待重传和超时。
所以“端口关闭时应该立即 refused”并不总成立;过滤策略决定了客户端看到明确拒绝还是长时间 timeout。
代理和负载均衡如何改变错误
客户端连接的是代理时,它首先观察到的是客户端到代理这一段。代理到后端的 ECONNREFUSED 可能被翻译成 HTTP 502;后端响应超时可能变成 504;代理主动终止客户端连接则可能让客户端看到 reset。
端到端排查必须关联客户端、入口代理、负载均衡和后端日志。仅凭客户端 errno 无法断定错误发生在哪一跳。
超时必须按层拆分
DNS 超时、TCP connect timeout、TLS handshake timeout、请求头超时、响应读取超时和连接池空闲超时含义不同。把所有层都设置为同一个值会使日志难以解释,也可能让外层先取消内层,丢失真实原因。
合理做法是分配总请求预算,并记录由哪一层触发取消。系统 TCP 重传时间与应用截止时间也不同,应用可能在内核最终认定 ETIMEDOUT 前主动结束等待。
安全重试的条件
网络错误并不自动意味着请求没有到达服务端。reset 或读取超时发生前,请求可能已被服务器执行,只是响应没有成功返回。对付款、创建订单等非幂等操作盲目重试会造成重复副作用。
重试前应确认方法语义、幂等键、服务端去重机制和剩余时间预算。refused 或路由不可达通常发生在建连前,但连接池和代理仍要求谨慎判断。
最小诊断证据集
至少保存时间戳、主机名、解析出的 IP、端口、地址族、原始 errno、系统调用阶段、超时配置、连接是否复用和请求 ID。服务端同步保存监听状态、连接日志、代理原因码和资源指标。
短时抓包可验证是否发出 SYN、是否收到 RST/ICMP、重传次数以及谁先发送 FIN 或 RST。抓包涉及敏感流量时必须按权限和脱敏要求操作。
分层排查步骤
第一步验证解析结果,第二步在实际运行环境查询到目标地址的路由,第三步确认目标端口监听与绑定地址,第四步核对防火墙、NAT 和负载均衡,最后检查 TLS 与应用日志。
容器或 Kubernetes 环境必须在相同 Pod、网络命名空间和服务账户上下文中复现;宿主机能访问并不能证明容器路径有效。
监控与告警怎么设计
不要只聚合为 network error。按目标、阶段、errno、地址族和代理节点统计,并监控比例而非孤立次数。ECONNREFUSED 突增常对应服务重启或错误后端;ETIMEDOUT 突增可能对应丢包或静默策略;EPIPE 突增常提示关闭时序或连接池问题。
同时保留低基数标签,避免把完整 URL 或用户标识直接作为指标维度造成成本和隐私问题。
FAQ:Connection refused 是否证明服务器在线?
它证明路径上有设备给出明确拒绝,但该设备可能是目标主机、防火墙或代理,不能仅凭错误确认业务服务健康。
FAQ:Connection timed out 是否一定是防火墙丢包?
不是。静默防火墙是常见原因之一,回程路由、严重丢包、主机无响应或应用设置的过短截止时间也可能造成超时。
FAQ:Connection reset by peer 一定由对端代码调用吗?
不一定。对端内核、负载均衡、NAT、防火墙或代理都可能生成 RST,需要抓包和分段日志确认发送者。
FAQ:忽略 SIGPIPE 就能解决 Broken pipe 吗?
不能。忽略信号只能避免进程被默认终止,send 仍会返回 EPIPE。程序必须停止写入并按请求语义处理失败。
FAQ:这些错误都适合自动重试吗?
不适合。只有在操作幂等、存在去重保护、错误具备瞬态特征且仍有时间预算时才应有限退避重试。
结论
六类错误的核心区别是失败阶段和反馈方式:refused 是明确拒绝,reset 是连接被强制终止,timeout 是等待超过期限,host/network unreachable 是路径不可达,EPIPE 是向已关闭写方向继续发送。保留原始 errno 和完整时间线,结合路由、抓包、代理与服务端证据,才能从“网络不通”收敛到可执行根因。
官方资料
- RFC 9293 TCP 规范:https:
/ / www. rfc- editor. org/ rfc/ rfc9293 - Linux connect(2) 手册:https:
/ / man7. org/ linux/ man- pages/ man2/ connect. 2. html - Linux send(2) 手册:https:
/ / man7. org/ linux/ man- pages/ man2/ send. 2. html - Linux tcp(7) 手册:https:
/ / man7. org/ linux/ man- pages/ man7/ tcp. 7. html - Linux ip(7) 手册:https:
/ / man7. org/ linux/ man- pages/ man7/ ip. 7. html - Linux errno(3) 手册:https:
/ / man7. org/ linux/ man- pages/ man3/ errno. 3. html - POSIX send 接口说明:https:
/ / man7. org/ linux/ man- pages/ man3/ send. 3p. html