从入门到精通的故障排查指南
目录导读
核心错误码速查表
网络编程中,错误码是系统和应用程序间沟通的语言,根据W3C和IETF标准,我们将最常见的错误码分为三类:HTTP状态码、系统错误码(如errno)和协议级错误码。
Q:为什么程序报错“Connection refused”但服务器明明在运行?
A:这是典型的ECONNREFUSED(错误码111)情况,通常因为目标端口未监听或防火墙拦截,建议先使用netstat -tlnp检查端口状态。
快速定位技巧:在Linux系统中,
/usr/include/asm-generic/errno-base.h和errno.h保存了所有系统错误码定义。
- EAGAIN(11):资源暂时不可用
- EINTR(4):系统调用被信号中断
- EPIPE(32):管道破裂(常见于写入已关闭的Socket)
HTTP领域常见错误码解析
1 4xx客户端错误
| 错误码 | 含义 | 典型场景 |
|---|---|---|
| 400 | Bad Request | 请求参数格式错误(如JSON语法错误) |
| 401 | Unauthorized | 缺少或无效的认证令牌 |
| 403 | Forbidden | 权限不足(如IP被拉黑) |
| 404 | Not Found | 资源路径错误(URL拼写或路由缺失) |
| 429 | Too Many Requests | 触发API速率限制 |
2 5xx服务器错误
| 错误码 | 含义 | 排查方向 |
|---|---|---|
| 500 | Internal Server Error | 后端代码异常(如数据库查询失败) |
| 502 | Bad Gateway | 反向代理与上游服务器连接失败 |
| 503 | Service Unavailable | 服务器超载或维护中 |
| 504 | Gateway Timeout | 上游服务器响应超时 |
Q:为什么偶尔出现502错误,过几秒又恢复正常?
A:这是典型的瞬时502场景,通常因为Nginx代理池中某个后端实例因内存溢出或CPU过载而临时不可用,建议检查/var/log/nginx/error.log中的“upstream timed out”条目。
实战建议:使用curl测试时添加
-v参数可显示完整HTTP头部,curl -v https://api.example.com/data重点关注
< HTTP/1.1 502 Bad Gateway后的响应头中的Date字段,可判断是代理层还是后端问题。
Socket/TCP错误码深度分析
1 核心系统错误码
| 系统错误码 | POSIX名称 | 触发条件 |
|---|---|---|
| 110 | ETIMEDOUT | TCP连接超时(默认重传未收到ACK) |
| 111 | ECONNREFUSED | 目标端口无监听服务 |
| 112 | EHOSTUNREACH | 目标主机不可达(路由表无条目) |
| 113 | ENETUNREACH | 网络不可达(如网线断开) |
| 104 | ECONNRESET | 对端突然关闭连接(如HTTP Keep-Alive超时) |
2 非阻塞I/O特有错误
- EINPROGRESS(115):非阻塞connect()操作正在进行,需epoll/wait监控socket状态。
- EWOULDBLOCK(11):send()/recv()无法立即完成,需配合select/poll轮询。
Q:如何区分“Connection reset by peer”和“Broken pipe”? A:当对端正常关闭连接(FIN)后,本地继续发数据时会收到EPIPE(32);若对端异常断开(RST),本地recv()会得到ECONNRESET(104),判断口诀:读reset,写pipe。
高级调试方法:使用
strace -e trace=network -p <PID>实时追踪系统调用错误:connect(3, {sa_family=AF_INET, sin_port=htons(80)}, 16) = -1 ETIMEDOUT (Connection timed out)
数据库连接错误码实战
1 MySQL/MariaDB常见错误
| 错误码 | 错误信息 | 解决方案 |
|---|---|---|
| 1045 | Access denied for user | 密码错误或IP白名单限制 |
| 2003 | Can't connect to MySQL server | 端口未开放(默认3306)或防火墙拦截 |
| 2013 | Lost connection during query | 网络延迟导致超时(需调整wait_timeout) |
| 1205 | Lock wait timeout exceeded | 死锁或长事务阻塞 |
2 PostgreSQL特有错误
- 28000:认证失败(密码或pg_hba.conf配置错误)
- 08006:连接失败(网络中断或数据库崩溃)
- 40P01:检测到死锁(需自动回滚事务)
Q:为什么max_connections明明设成200,但客户端连接时仍报1040错误?
A:1040(Too many connections)的计数包含后台连接(如复制连接、后台工作者),建议查看SHOW STATUS LIKE 'Threads_connected';与实际配置的差值,并检查super_connections预留值。
优化建议:在应用层配置连接池(如HikariCP或Druid),将最大连接数设为数据库允许值的80%,同时开启Keep-Alive(默认300秒)。
DNS与SSL/TLS错误码解密
1 DNS解析错误
| 错误类型 | Windows错误码 | Linux错误码 | 原因 |
|---|---|---|---|
| 主机名未找到 | 11001 | EAI_NONAME (-2) | 域名不存在或DNS服务器无记录 |
| DNS服务器无响应 | 11002 | EAI_AGAIN | DNS超时(可检查/etc/resolv.conf) |
| 无效域名格式 | 11005 | EAI_BADHINTS | 域名包含非法字符 |
2 SSL/TLS握手失败
| OpenSSL错误 | 含义 | 排查步骤 |
|---|---|---|
| SSL_ERROR_SYSCALL | 底层Socket中断 | 检查防火墙是否放行443端口 |
| SSL_ERROR_SSL (1) | 证书验证失败 | 使用openssl s_client -connect host:port |
| SSL_ERROR_ZERO_RETURN | 连接正常关闭但未完成握手 | 确认TLS版本是否匹配 |
Q:为什么curl访问HTTPS时报“SSL certificate problem: unable to get local issuer certificate”? A:这是典型的CA根证书缺失问题,解决方案:
- 更新系统证书:
sudo update-ca-certificates - 或临时跳过验证(仅测试用):
curl -k https://... - 若为公司内网自签名证书,需将.pem证书导入
/etc/ssl/certs/
进阶工具:使用
sslyze --regular example.com可扫描服务器的SSL配置缺陷,包括弱加密套件和未禁用的TLS 1.0协议。
高频问答集锦
Q1:程序返回-1(通用错误),如何快速定位?
A:在C/C++中使用perror(strerror(errno))打印错误描述;Python中使用traceback.print_exc();Java中检查异常链的getCause()。
Q2:Socket通信中突然出现“Bad file descriptor”错误
A:表示传入的文件描述符(fd)已经被关闭或无效,常见原因:多线程中某个线程关闭了共享Socket,而另一线程仍在读写,排查时添加O_CLOEXEC标志。
Q3:Nginx日志中出现“upstream sent too big header”错误
A:调整proxy_buffer_size(默认4KB)和proxy_buffers(默认8*4KB),
proxy_buffer_size 16k; proxy_buffers 4 32k;
Q4:为什么curl请求返回“Operation timed out”但ping正常?
A:ping走ICMP协议,而curl使用TCP,可能原因:防火墙拦截了HTTP端口,或目标服务器负载过高导致SYN包被丢弃,使用traceroute -T -p 80 host查看TCP路由。
Q5:Python中如何捕获“ConnectionAbortedError”?
A:该错误对应系统错误码ECONNRESET,示例代码:
try:
sock.sendall(data)
except ConnectionAbortedError as e:
logging.error(f"连接被重置: {e.errno}")
网络编程的本质是处理非理想网络环境,掌握错误码的语义和对应的系统行为,能让开发者从“魔法数字”的困惑中解放,转向精准的故障根因分析,建议在日常开发中养成三个习惯:始终检查错误码、记录完整的堆栈信息、使用抓包工具(如tcpdump或Wireshark)验证假设。