CentOS服务器上运行的服务突然报出Connection timed out,errno 110这个错误码在socket编程中代表连接超时,但它的实际含义和触发条件远比表面复杂。很多情况下,ping是通的,端口也是监听的,应用却反复抛出errno 110;有时候内网两台机器之间也会出现这个错误,而防火墙规则并没有明显变化。这篇文章从网络栈的底层行为出发,把errno 110的排查路径理清楚。

errno 110到底意味着什么
在Linux的socket编程中,connect()系统调用在非阻塞模式下会立即返回EINPROGRESS,表示连接正在建立。之后内核会按tcp_syn_retries规定的次数重发SYN包,如果所有重试都失败,连接最终以ETIMEDOUT(errno 110)结束。注意这里的关键点:errno 110不是应用层设置的超时,而是内核TCP协议栈在放弃连接前的最终结果。应用代码里如果设置了connect timeout,比如3秒,但内核SYN重试总时长可能超过10秒,那么应用会先触发自己的超时逻辑,而内核还会继续重试SYN,直到内核放弃。这就是为什么有时候应用日志里报的是“connect timeout”而系统日志中却能看到SYN重传的原因。
还有一种情况是connect()调用本身阻塞等待,但默认的阻塞connect超时时间与tcp_syn_retries相关,在CentOS默认配置下tcp_syn_retries=6,意味着SYN重试6次,总等待时间大约127秒。如果应用没有在代码里设置SO_SNDTIMEO或者connect超时,那么一个无法到达的目标地址会让线程阻塞两分钟以上才返回errno 110。这篇文章只讨论连接建立阶段的超时,不涉及数据读写阶段的SO_RCVTIMEO或SO_SNDTIMEO。
要确认errno 110确实来自内核而不是应用层逻辑,可以用strace跟踪一个简单的连接测试程序。例如使用curl访问一个不存在的内网IP,观察connect调用返回的errno值:
strace -e trace=connect curl -v --connect-timeout 5 http://192.168.200.200:8080 2>&1 | grep EINPROGRESS -A2
# 期望看到类似输出:
# connect(3, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.168.200.200")}, 16) = -1 EINPROGRESS (Operation now in progress)
# 之后poll等待,最后可能返回ETIMEDOUT
这段输出里connect返回EINPROGRESS说明socket是非阻塞模式或者使用了带超时的封装。最终poll返回超时后,应用会得到errno 110。如果strace中直接看到connect返回-1 ETIMEDOUT,那就说明内核在SYN重试阶段就放弃了,此时排查重点应放在网络可达性、防火墙策略和路由表上。
网络层排查:从SYN包的生命周期入手
当应用报出errno 110时,首先要弄清楚SYN包有没有发出去、有没有收到响应。最直接的工具是tcpdump,在客户端和服务器端同时抓包对比。假设客户端IP是192.168.10.20,服务器IP是192.168.10.30,目标端口8080。在客户端执行:
tcpdump -i eth0 host 192.168.10.30 and port 8080 -nn -S
观察输出中是否有SYN包发出,以及是否有SYN-ACK返回。如果只有SYN没有SYN-ACK,说明服务器没有响应。可能的原因包括:服务器防火墙DROP了SYN包(iptables -A INPUT -p tcp --dport 8080 -j DROP)、服务器上服务没有真正监听(ss -lntp | grep 8080)、或者是中间交换机/路由器丢弃了特定端口的流量。如果客户端根本没有发出SYN包,那问题可能出在本地路由或者出接口选择上,比如多网卡场景下流量走了错误的接口。
一个常见的误区是:telnet 192.168.10.30 8080能通,但应用却报errno 110。telnet默认使用阻塞connect,且没有设置超时,它可能等待了很长时间才连上,而应用设置了较短的connect timeout,在SYN重试尚未完成时就放弃了。另外,telnet连接成功只代表TCP三次握手完成,不代表应用层协议正常。如果服务器accept队列已满,新连接可能被丢弃,客户端仍然会看到SYN-ACK返回但随后连接被重置,表现与应用超时类似。
用ss命令排查服务器端连接队列状态非常关键。执行ss -lntp | grep 8080可以看到监听socket的Send-Q和Recv-Q。Recv-Q表示当前已建立但尚未被应用accept的连接数,如果这个值持续接近或等于backlog参数(通常由listen函数的第二个参数决定,默认128),说明应用处理连接的速度跟不上,新连接会被内核丢弃。客户端表现就是connect超时或者连接被拒绝。此时需要调整应用的accept线程数,或者修改net.core.somaxconn和应用的backlog值。
内核参数与TIME_WAIT堆积的影响
CentOS默认的内核网络参数在某些高并发场景下会加剧errno 110的出现频率。最典型的是net.ipv4.tcp_syn_retries和net.ipv4.tcp_synack_retries。前者控制客户端SYN重试次数,后者控制服务器端SYN-ACK重试次数。两者默认值都是6,对应几十秒到两分钟的等待。如果内网中有一批机器突然宕机但IP还在路由表中,客户端连接这些机器时就会经历漫长的SYN重试,大量线程阻塞在connect阶段,最终导致业务超时。对于内网低延迟环境,可以将tcp_syn_retries降为2或3,缩短失败判定时间。
另一个常被忽视的参数是net.ipv4.tcp_tw_reuse和net.ipv4.tcp_timestamps。TIME_WAIT状态本身不会直接导致errno 110,但如果服务器端存在大量TIME_WAIT并且源端口范围不够用,新的主动连接会因为没有可用端口而失败,报出EADDRNOTAVAIL而不是errno 110。不过,当客户端本地端口耗尽时,connect调用也可能返回ETIMEDOUT,原因是内核在选择端口时发现所有候选端口都处于忙状态,最终放弃。检查ss -s可以看到当前TCP连接统计,如果TIME-WAIT数量超过几千,且net.ipv4.ip_local_port_range配置的端口范围太小,就需要扩大范围或启用tcp_tw_reuse。
调整内核参数需要谨慎,建议在测试环境验证后再应用到生产。临时修改可以使用sysctl -w命令,永久修改需要写入/etc/sysctl.conf或/etc/sysctl.d/下的配置文件。以下是一个针对高并发内网服务的参数调整示例:
# 查看当前SYN重试相关参数 sysctl net.ipv4.tcp_syn_retries net.ipv4.tcp_synack_retries net.ipv4.ip_local_port_range net.ipv4.tcp_tw_reuse # 临时调整(重启失效) sysctl -w net.ipv4.tcp_syn_retries=3 sysctl -w net.ipv4.tcp_synack_retries=3 sysctl -w net.ipv4.ip_local_port_range="1024 65535" sysctl -w net.ipv4.tcp_tw_reuse=1 # 永久生效 echo "net.ipv4.tcp_syn_retries=3" >> /etc/sysctl.d/99-network-tuning.conf echo "net.ipv4.tcp_synack_retries=3" >> /etc/sysctl.d/99-network-tuning.conf echo "net.ipv4.ip_local_port_range=1024 65535" >> /etc/sysctl.d/99-network-tuning.conf echo "net.ipv4.tcp_tw_reuse=1" >> /etc/sysctl.d/99-network-tuning.conf sysctl -p /etc/sysctl.d/99-network-tuning.conf
需要强调的是,tcp_tw_reuse只能用于客户端主动连接,且必须同时开启tcp_timestamps(默认已开启)。如果服务器端也大量主动外连(例如反向代理),TIME_WAIT堆积同样会影响性能。对于服务器端被动接收连接的情况,应该关注的是tcp_max_tw_buckets和tcp_tw_recycle。注意tcp_tw_recycle在NAT环境下会导致连接被丢弃,CentOS 7及以后版本已将其移除,不应再使用。
最后补充一个排查技巧:使用ip route get命令确认去往目标IP的流量实际走哪个接口和网关。在多网卡、多路由表的复杂网络环境中,流量可能被发送到错误的接口,导致SYN包根本没有到达目标网络。例如:
ip route get 192.168.10.30 # 输出类似:192.168.10.30 dev eth1 src 192.168.10.20 uid 0 # 确认dev是否为预期接口,src是否为预期源IP
如果输出显示流量走了eth1而实际目标在eth0所在网段,就需要检查路由表、策略路由或者bond配置。另一个容易被忽略的点是ARP问题:如果目标IP的MAC地址解析失败,SYN包无法封装成以太网帧,内核同样会重试并最终报ETIMEDOUT。用arp -n查看目标IP是否有有效的MAC条目,如果显示incomplete,说明二层连通性有问题,需要检查交换机vlan、网卡状态或物理链路。
errno 110连接超时CentOS网络排查修改时间:2026-09-20 23:45:43