网络命令
这一课你将能做到
- 用 curl 完成 GET/POST 请求、带头带体带超时,并用 -w 输出状态码和耗时做接口巡检
- 用 ss -tlnp 查端口监听与归属进程,判断「服务到底起没起来」
- 用 ping / dig / ssh / scp 完成基础连通性、域名解析和远程文件传输
为什么要学
「接口打不通」是后端最高频的线上问题之一,而它从来不是一个问题,是四个候选答案:进程没起?端口没监听?防火墙拦了?域名解析错了?每种答案对应一条 Shell 命令。curl 还是你测试 Spring Boot 接口的终端版 Postman——CI 流水线里的健康检查、发布脚本的探活循环、联调时快速验证参数,全是 curl。面试聊「502 怎么排查」,Nginx→后端这条链路的每个环节都得能用命令验证。
人话:curl 是「终端里的浏览器」,ss 是「端口门卫登记表」,ping 测「路通不通」,dig 查「门牌号对不对」,ssh/scp 是「远程遥控器 + 快递员」。五件套在手,网络问题的排查路径就闭环了。
先建立图像
一次 HTTP 请求的排查地图:
浏览器/curl ──→ DNS 解析 ──→ TCP 连接 ──→ Nginx ──→ Spring Boot
│ │ │ │ │
curl 命令 dig 域名 ss/ping nginx -t ps/jstack
查解析对不对 看端口监听 查配置语法 查应用状态
「服务没起来」的四层候选与对应命令:
| 症状 | 可能原因 | 验证命令 |
|---|
| curl: connection refused | 进程没起或端口没监听 | ss -tlnp | grep 8080 |
| 卡住后 timeout | 防火墙/安全组拦截 | ping、云控制台安全组 |
| 404 | 进程在,路由不对 | curl -i 看响应头 |
| 502 | Nginx 在,后端挂了 | curl 后端端口 + ps |
跟着做
步骤 1:curl 基本功:GET 与状态码
curl https://httpbin.org/get # 输出响应体
curl -i https://httpbin.org/get # 连响应头一起看
curl -s -o /dev/null -w "%{http_code}\n" https://httpbin.org/status/200
# 输出:200 ← 巡检脚本里最有用的一行
curl -sL -o /dev/null -w "%{http_code} %{time_total}s\n" http://example.com
# -L 跟随重定向;%{time_total} 总耗时,性能初判
-s 静默(不显示进度条),-o /dev/null 丢弃响应体只要状态码,-w 自定义输出格式——这三件套组合是接口巡检的工业标准写法。
步骤 2:POST 与常见参数
# JSON POST(对接 Spring Boot 接口)
curl -s -X POST http://localhost:8080/api/order \
-H "Content-Type: application/json" \
-H "Authorization: Bearer token123" \
-d '{"productId":1,"count":2}'
# 表单 POST
curl -s -X POST -d "username=tom&password=123" http://localhost:8080/login
# 必加超时!否则脚本会被无响应接口挂死
curl -s -m 5 --connect-timeout 2 http://localhost:8080/actuator/health
整体最多 5 秒, 建连最多 2 秒。写进脚本的 curl 不带超时是事故预备役。
-m 5
--connect-timeout 2
步骤 3:本机起个服务练手
没有现成接口也能练,Python 一行起个服务(绝大多数 Linux 自带):
cd ~/net-lab 2>/dev/null || mkdir -p ~/net-lab && cd ~/net-lab
echo "hello from server" > index.html
nohup python3 -m http.server 8000 > server.log 2>&1 &
sleep 1
curl -s http://localhost:8000/ # hello from server
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8000/ # 200
步骤 4:ss 查端口监听(netstat 的现代替代)
ss -tlnp | grep 8000
# LISTEN 0 511 0.0.0.0:8000 0.0.0.0:* users:(("python3",pid=1234,fd=3))
# -t TCP -l 监听中 -n 数字显示 -p 显示进程
ss -tlnp | grep -E ':(80|443|8080)\s' # 一次查三个常用端口
ss -tn state established | head # 当前已建立的连接(看谁连着我)
ss -s # 连接状态汇总(TIME_WAIT 多不多一眼看出)
老系统没有 ss 用 netstat -tlnp,参数几乎同名。看到 0.0.0.0:8080 是对所有网卡监听(外部可访问),127.0.0.1:8080 只有本机能访问——排查「本地好好的外部访问不了」第一查这个。
步骤 5:ping 与 dig
ping -c 3 baidu.com # 发 3 个包就停;通=网络层可达
dig +short api.example.com # 查域名解析结果
dig +short api.example.com @8.8.8.8 # 指定 DNS 服务器对比
「解析不对」的经典现场:本机 dig 出来的 IP 和预期不符,八成是 hosts 文件或内网 DNS 劫持——grep 域名 /etc/hosts 先查本地映射。
步骤 6:ssh 与 scp 远程操作
ssh 用户名@服务器IP # 交互登录
ssh -p 2222 deploy@10.0.0.5 # 非默认端口
ssh deploy@10.0.0.5 'uptime && df -h' # 非交互执行远程命令,批量巡检的基础
scp app.jar deploy@10.0.0.5:/opt/myapp/ # 推文件到远程
scp deploy@10.0.0.5:/var/log/app.log ./ # 从远程拉文件
scp -r config/ deploy@10.0.0.5:/opt/myapp/ # 递归推目录
ssh 主机 '命令' 是「批量巡检脚本」的原子能力:外层 for 循环节点列表,内层远程执行检查命令,第 12 课综合练习组装它。
步骤 7:组装一个接口巡检脚本
cat > health-check.sh << 'EOF'
#!/bin/bash
set -uo pipefail
URLS=(
"http://localhost:8000/"
"http://localhost:9999/" # 故意放一个不存在的端口
)
for url in "${URLS[@]}"; do
code=$(curl -s -m 3 -o /dev/null -w "%{http_code}" "$url" || echo "ERR")
if [ "$code" = "200" ]; then
echo "OK $url"
else
echo "FAIL $url (code=$code)"
fi
done
EOF
bash health-check.sh
# OK http://localhost:8000/
# FAIL http://localhost:9999/ (code=ERR)
注意这里用 set -uo pipefail 而没加 -e:因为 curl 失败恰恰是我们要采集的信息,不能让它中途退出——工具服务于目的。
讲清楚要点
- curl 排查接口问题的顺序:先
-i 看响应头有没有(连接层问题还是应用层问题),再换状态码区分 404/502/超时,最后 -v 看完整握手过程。-v 输出里能直接看到 TCP 建连、TLS、请求头三个阶段卡在哪。
- ss -tlnp 的输出要会读三样:监听地址(0.0.0.0 全网卡 / 127.0.0.1 仅本机)、端口、进程名+PID。Nginx 起来了但
ss 里没有 80/443 → 配置语法错或被占用,nginx -t 验证。
- TIME_WAIT 是正常的连接收尾状态,几千个不必慌;真正要警惕的是大量
CLOSE_WAIT——那是对端已关闭、我方应用没调 close,通常意味着代码里连接泄漏(HttpClient 没关、连接池配置错误)。
- 502 的本质是 Nginx 连不上后端:排查动作 =
curl 后端健康接口 + ss -tlnp | grep 后端端口 + tail nginx error log。三步定位是「Nginx 挂了」还是「后端挂了」还是「网络不通」。
- 防火墙有两层:系统层
firewalld/iptables(sudo firewall-cmd --list-ports 或 sudo iptables -L -n),云层安全组在控制台配。本地 curl 通、外部不通,九成是这两层之一。
- ssh 免密是自动化的前置条件:
ssh-keygen -t ed25519 生成密钥,ssh-copy-id 用户@主机 分发公钥,之后脚本里的 ssh/scp 不再要密码。生产密钥必须加 passphrase 存入 agent。
你可能会懵的地方
-
curl 返回 000 是什么意思?
连接根本没建立(拒绝、超时、DNS 失败),没有 HTTP 状态码可言。curl -v 看具体卡在哪一步。脚本里 000/ERR 要当独立分支处理,别和 404 混为一谈。
-
127.0.0.1、0.0.0.0、localhost 有什么区别?
127.0.0.1 是回环地址(本机自己);0.0.0.0 是「所有网卡」(监听地址里出现=外部可访问;路由里出现=默认路由);localhost 是主机名,默认解析到 127.0.0.1。应用绑 127.0.0.1 时外部永远访问不了,改绑定 0.0.0.0 并配合防火墙。
-
ping 通但 curl 不通,为什么?
ping 走 ICMP,curl 走 TCP。防火墙常放行 ICMP 拦截 TCP 端口。所以「ping 得通」只证明主机可达,不证明服务可用——排查要逐层来,不能跳步。
-
nc(netcat)什么时候用?
纯 TCP 探活:nc -zv 10.0.0.5 3306,验证 MySQL 端口通不通比 curl 直接(curl 是 HTTP 语义)。批量验端口段也方便:for p in 80 443 3306 6379; do nc -z -w1 本机IP $p && echo "$p 通" || echo "$p 不通"; done。
-
scp 和 rsync 怎么选?
scp 简单直接,一次性传文件;rsync 增量传输(只传差异块)、支持断点续传和排除规则,大目录同步、日常备份用它:rsync -avz --exclude='logs/' config/ deploy@host:/opt/myapp/config/。
错法对照
| 错法 | 问题 | 正解 |
|---|
| 脚本里 curl 不加超时 | 无响应接口把发布流水线挂死 | -m 5 --connect-timeout 2 |
| 拿 0.0.0.0 去请求 | 它是监听通配不是目标地址 | 请求用 127.0.0.1 或具体 IP |
| 只 ping 通就认为服务正常 | ICMP 通≠TCP 端口通 | 加 ss -tlnp + curl 验证 |
| 看到大量 TIME_WAIT 就以为出事 | 正常短连接收尾状态 | 警惕的应是 CLOSE_WAIT 堆积 |
| scp 传目录漏 -r | 报 not a directory 或跳过 | scp -r,或改用 rsync -a |
卡点急救
- connection refused:进程没起或没监听该端口。
ss -tlnp | grep 端口 验证;没有输出就 ps -ef | grep 应用 看进程,都没有就去翻应用启动日志找崩溃原因。
- curl 卡住不动:目标 IP 不可达或防火墙丢包(不拒绝只吞)。
Ctrl+C 后加 -m 5 --connect-timeout 2 重试;再查 ping 和云安全组。
- ssh 报 Permission denied (publickey):服务器未收录你的公钥或密钥权限不对。重新
ssh-copy-id;确认本机私钥 ~/.ssh/id_ed25519 权限是 600,服务器上 ~/.ssh 是 700。
面试常问
-
线上接口 502,Nginx 报 connect() failed,你的排查步骤?
① ss -tlnp | grep 后端端口 看后端有没有监听;② curl -m 3 http://127.0.0.1:端口/actuator/health 直接打后端绕过 Nginx;③ ps -ef | grep java 确认进程;④ tail -n 100 nginx错误日志和后端日志 找启动失败/崩溃原因。结论通常是后端进程挂了或端口配错——能按层次说出验证命令就是好答案。
-
怎么判断一台服务器的某个端口是否对外可访问?
在本机 ss -tlnp | grep 端口 确认监听且地址为 0.0.0.0;在另一台机器 nc -zv 服务器IP 端口 或 curl -m 3 服务器IP:端口 验证外部可达;不通再查 firewalld/iptables 与云安全组。三层验证:监听 → 系统防火墙 → 云层。
-
CLOSE_WAIT 大量堆积说明什么?
对端已关闭连接,本端应用迟迟没有调用 close(),一般是代码层连接泄漏:HttpClient/数据库连接用完未归还或未关闭、连接池 maxLifetime 配置不当。先 ss -tanp | grep CLOSE_WAIT 统计归属进程,再 review 对应代码的连接关闭逻辑,临时缓解可重启应用。
自测三问
ss -tlnp 四个字母分别是什么含义?
- 用 curl 输出某接口的 HTTP 状态码和总耗时,命令怎么写?
- 0.0.0.0 作为监听地址和作为访问目标时,含义分别是什么?
小结一句话
网络排查是分层验证:dig 查解析、ping 查可达、ss 查监听、curl 查应用、防火墙查拦截——每层一条命令,502 就再也不是玄学。
延伸
- curl 官方文档
- 下一课:系统管理与编辑器——磁盘、内存、软件包,外加 vim 生存法则。