文件与存储管理解决“数据落在哪里”,网络要解决“数据怎样抵达另一个进程”。“网络不通”不是一个足够精确的故障描述。接口可能根本不存在,也可能只是没有地址;名称解析可能失败,但直接访问 IP 正常;TCP 已经建立,HTTP 仍可能返回错误状态;SSH 端口可达,也不代表主机密钥可信或用户认证会通过。
更稳妥的做法,是把一次网络访问拆成连续的证据链:链路 → 地址 → 路由 → 名称解析 → 端口 → 应用协议。每一层都用对应工具回答一个明确问题,并同时写下“已经证明什么”和“尚未证明什么”。这样做的好处很实际:我们不会因为 ping 成功就宣布服务正常,也不会看到 HTTP 404 就误判成线路中断。
这一章从接口、MAC、IP、端口的分层身份开始,逐步进入 CIDR、路由、邻居表、DNS、ICMP、socket、HTTP 和 SSH。所有会产生服务的实操都限制在一次性容器的回环地址中,结束后停止进程、删除实验目录并移除容器。

一次 curl https://service.example/health 成功,背后至少发生了这些动作:接口可以承载数据;系统持有合适的源地址;内核为目标选出路由;解析器把名称转换成一个或多个地址;客户端与目标端口建立传输层通信;TLS、HTTP 和业务代码最后返回可解释的结果。
这六层适合用一张表先对齐:
排查时要从下往上走。假如 ip link 已经显示接口缺失,继续修改 DNS 没有帮助;假如 curl 收到 404,反过来说明链路、地址、路由、端口和 HTTP 服务大多已经走通,应该检查 URL 路径或应用路由。
“通”必须带对象。我们可以说“ICMP Echo 往返成功”“TCP 443 握手成功”或“GET /health 返回 200”,不要只写“网络正常”。对象越具体,下一位排查者越容易复现判断。
网络排障经常从“地址”这个词开始混乱。接口名、MAC、IP、端口和域名都能帮助定位,但它们工作在不同范围。
lo、eth0、enp2s0,是当前网络命名空间里内核网络接口对象的名字。它不是全球标识,也可能受发行版命名策略影响。53/udp 与 53/tcp 是两个不同入口,端口必须和协议、绑定地址一起看。/etc/hosts、NSS 模块、DNS、缓存或应用自身逻辑转换,不能把名称当作一个永远不变的 IP。一条 TCP 连接常用四元组标识:源 IP、源端口、目的 IP、目的端口。若再加上传输协议,就能区分同一对地址上的 TCP 与 UDP。客户端通常选择临时源端口,服务端在约定端口监听。例如 127.0.0.1:53120 → 127.0.0.1:19090 中,53120 是客户端临时端口,19090 是服务端入口。

ip 的不同对象回答不同问题。最先运行的通常是:
ip -br link
ip -s link show dev eth0
ip -br address
ip address show dev eth0ip -br link 的简洁输出适合快速盘点。常见标志含义如下:
ip -s link 还会显示收发包、字节、丢弃和错误计数。计数必须观察差值:一个从运行多年环境里累积出的非零错误,不一定对应眼前故障;若重试操作时错误计数同步增长,关联才更强。
地址观察要关注四件事:地址族、前缀长度、作用域和生命周期。下面的回环输出同时有 IPv4 与 IPv6:
lo UNKNOWN 127.0.0.1/8 ::1/128一次性容器中还出现 eth0 172.17.0.2/16。这只证明接口持有该地址,并不能单凭 /16 推断默认网关;网关必须到路由表中确认。DHCP 或 IPv6 自动配置是地址的来源之一,观察命令展示的是最终内核状态,不等于配置由哪一个管理器负责。

IPv4 地址有 32 位。CIDR 的 /n 表示前 n 位是网络前缀,其余位是主机部分。判断两个地址是否同网段,要分别做相同运算:
网络地址 = IP 地址 AND 子网掩码以 192.168.10.37/24 为例,/24 的掩码是 255.255.255.0,网络地址是 192.168.10.0,传统广播地址是 192.168.10.255。192.168.10.220/24 得到相同网络地址,因此通常通过同一链路的邻居解析直接交付;192.168.11.5/24 得到另一个网络地址,需要更具体路由或默认路由。
前缀不是固定在字节边界。10.20.30.77/26 的掩码是 255.255.255.192,每个子网包含 64 个地址。77 落在 64–127 这段,因此网络是 10.20.30.64/26。看到前三段相同并不能替代二进制计算。
/31 常用于点到点链路,两个地址不按传统网络号/广播号规则浪费;/32 表示单一 IPv4 地址。私有 IPv4 范围常见为 10.0.0.0/8、172.16.0.0/12 和 192.168.0.0/16。私有地址通常通过网关上的 NAT 访问外部网络,但 NAT 是否存在、如何转换,不能由私有地址本身推出。

IPv6 地址有 128 位,通常写成八组十六进制数。每组可省略前导零,一串连续的全零组可以用一次 :: 压缩。例如:
2001:0db8:0000:0000:0000:0000:0000:0042
2001:db8::42这两种写法表示同一个地址。:: 在一个地址中只能出现一次,否则无法确定省略了多少组。
接口经常同时拥有多种作用域:
::1/128 是 IPv6 回环地址。fe80::/10 是链路本地范围。同一个链路本地地址可能在多个接口上出现,因此命令中常需带区域标识,例如 ping -6 fe80::1%eth0。/64,但不能把 /64 当成所有场景的硬规则。::/0 是 IPv6 默认路由,与 IPv4 的 0.0.0.0/0 分开维护。双栈表示 IPv4 与 IPv6 同时存在,不表示两者状态同步。一个域名可能同时返回 A 与 AAAA 记录;应用会根据地址选择算法、连接结果和实现策略决定先尝试哪个。诊断时用 ip -4、ip -6、ping -4、ping -6 或 curl -4/-6 固定地址族,才能避免把“IPv6 失败后回退到 IPv4”误写成“IPv6 正常”。
路由表描述“某类目的地址应该交给谁”。典型 IPv4 表可能是:
default via 192.168.50.1 dev eth0 metric 100
10.20.0.0/16 via 10.255.0.1 dev wg0 metric 80
10.20.30.0/24 dev eth1 scope link metric 200
10.20.30.64/26 via 10.20.30.1 dev eth1 metric 50目标 10.20.30.77 同时匹配 /0、/16、/24 和 /26。内核先选择最长的 /26;只有候选前缀同样长时,metric 等条件才进入比较。默认路由之所以最后使用,是因为 /0 最不具体,不是因为它一定显示在最后一行。
ip route show 展示规则,ip route get 则让内核按一个具体目标执行查找:
ip route get 203.0.113.7
ip -6 route get 2001:db8::7一次性容器中对文档保留地址运行第一条命令,得到:
203.0.113.7 via 172.17.0.1 dev eth0 src 172.17.0.2 uid 0这里已经证明内核会选择源地址 172.17.0.2、接口 eth0 和下一跳 172.17.0.1。命令没有发送数据包,因此不能证明下一跳存在、目标可达或返回路径正确。多路由表、源地址规则、VRF 和数据包标记还可能让选择比主表更复杂;遇到这种环境要继续检查 ip rule 与相应表,而不是只看默认主表。

路由选择完成后,如果下一跳位于以太网等多址链路,系统还要知道“这个下一跳 IP 对应哪个链路地址”。IPv4 使用 ARP,IPv6 使用 Neighbor Discovery。ip neigh 把两者放在统一界面:
ip neigh show
ip neigh show dev eth0
ip neigh get 192.168.50.1 dev eth0一次性容器在安装软件包后,邻居表中出现:
172.17.0.1 dev eth0 lladdr 72:ed:0b:a9:10:27 REACHABLE这行表示协议地址 172.17.0.1 在 eth0 链路上对应某个 MAC,近期可达性确认仍有效。常见状态不是简单的好/坏开关:
STALE 很常见,不应一看到就清缓存。INCOMPLETE 或 FAILED 若与通信失败同步出现,才提示应检查 VLAN、二层隔离、错误网关、地址冲突或链路策略。邻居表只涉及同链路的下一跳;访问远端地址时,表中通常出现网关 MAC,而不是远端服务器 MAC。
应用通常不直接打开 /etc/resolv.conf 后自己发 DNS 报文。常见路径是调用 getaddrinfo(),再由 C 库的 Name Service Switch 按 /etc/nsswitch.conf 决定数据源。下面这一行很关键:
hosts: files dns它通常表示先查 /etc/hosts,没有命中再查 DNS。实际系统还可能出现 resolve、myhostname、mdns 等模块和带条件的返回规则,所以不要假设所有发行版都严格只有这两个词。
getent 能复用这条路径:
getent ahosts service.example
getent ahostsv4 service.example
getent ahostsv6 service.example一次性容器在 /etc/hosts 增加 127.0.0.77 ch16.test 后,getent ahostsv4 ch16.test 返回:
127.0.0.77 STREAM ch16.test
127.0.0.77 DGRAM
127.0.0.77 RAW这证明 NSS 先从静态映射得到地址,并为不同 socket 类型返回结果。直接使用 dig 查询某台 DNS 服务器回答的是“该服务器如何回答 DNS”,它不会证明 /etc/hosts、NSS 顺序或应用缓存的最终结果。
/etc/resolv.conf 可能直接列出 nameserver,也可能是网络管理器生成的文件,或者链接到 systemd-resolved 的 stub。先用 readlink -f /etc/resolv.conf、cat /etc/resolv.conf 和 resolvectl status 确认结构,再决定修改入口。手工覆盖一个受管理文件,下一次网络切换就可能被重写。

ping 发送 ICMP Echo Request,等待 Echo Reply。一个可重复的短测试可以写成:
ping -4 -c 4 -W 2 192.0.2.20
ping -6 -c 4 -W 2 2001:db8::20-c 4 限制数量,-W 2 限制等待单个回复的时间。结果中的丢包率、往返时间和波动需要结合测试位置、链路类型和时间窗口解释。
成功时可以证明:名称已经解析成功(如果输入的是名称)、选择的地址族有路由、ICMP Echo 请求和回复能在当时往返。它仍不能证明 TCP 443 在监听、TLS 证书有效或 HTTP 页面正确。
失败的含义更宽:目标或中间设备可能不响应 Echo,防火墙可能过滤 ICMP,路由可能断裂,也可能只是地址族选错。ICMP 的职责是反馈网络层信息,但并不保证每个失败都一定返回控制报文。因此,100% packet loss 不能单独证明目标关机。
对排障而言,更有用的问法是:
ping 输入名称时是否先显示了解析后的地址?-4 与 -6 后结果是否不同?ip route get 是否选中了预期出口?
IP 每经过一个三层转发节点,TTL(IPv4)或 Hop Limit(IPv6)通常减 1。探测工具从较小的限制开始发送报文;某一跳把限制减到 0 时,可能返回 ICMP Time Exceeded,于是工具逐步得到中间节点信息。
Linux 上可先使用无需特权的 tracepath:
tracepath -n 目标地址
tracepath -6 -n IPv6目标它还能观察路径 MTU。traceroute 提供更多探测方法,不同发行版的默认 UDP、ICMP 或 TCP 行为可能不同。排查受防火墙影响的路径时,必须记录实际探测类型,不能只比较工具名。
一行 * * * 只表示该次探测没有在等待窗口内收到可显示的回复,可能是路由器限速、过滤、不生成 ICMP、返回路径不同或真实丢包。后续跳仍出现时,更不能把星号所在节点直接定罪。还有三个边界:
因此,路径工具适合提出假设,例如“从某一跳之后回复模式改变”,而不是单次运行后宣布“某台路由器坏了”。应结合目标端口测试、多个观察点、时间序列和负责该网络的运维数据。
ss 是现代 Linux 上观察 socket 的主工具。常用组合可以拆成:
ss -lntp # TCP 监听,数字地址,显示进程
ss -lnup # UDP socket
ss -ntp # 非监听 TCP 连接
ss -s # 汇总统计
ss -lntp '( sport = :8080 )'数字显示 -n 很重要:它避免端口名和反向 DNS 查询把“连接观察”混入“名称解析”,速度也更稳定。-p 显示进程信息可能受权限限制;看不到进程不代表没有 socket。
监听地址决定入口范围:
一次性容器中的回环 HTTP 服务给出:
LISTEN 0 5 127.0.0.1:18080 0.0.0.0:* users:(("python3",pid=3273,fd=3))这已经证明 python3 在 IPv4 回环 18080 监听。它没有证明其他接口能访问,也没有证明任意 URL 都返回 200。
另一个临时 TCP 服务与 nc 客户端连接时,ss 同时显示:
127.0.0.1:19090 127.0.0.1:53120 users:(("python3",pid=3288,fd=4))
127.0.0.1:53120 127.0.0.1:19090 users:(("nc",pid=3295,fd=3))这两行是同一条回环连接从两端观察的结果。ESTAB 证明 TCP 握手完成,但应用还可能卡在认证、协议版本或请求内容。
检查 HTTP 时,curl 能把多个阶段串在一起:
curl -v --connect-timeout 3 --max-time 10 https://service.example/health
curl -sS -o /dev/null \
-w 'code=%{http_code} remote=%{remote_ip}:%{remote_port} total=%{time_total}\n' \
https://service.example/health-v 会显示解析到的地址、连接目标、TLS 信息和 HTTP 头,适合交互排障。输出可能带 Authorization、Cookie 或内部地址,分享前必须脱敏。--connect-timeout 约束建连阶段,--max-time 约束整次传输,二者不能混为一个“超时”。
wget 更偏向下载,也可以只检查响应:
wget --spider --server-response --timeout=3 http://127.0.0.1:18080/--spider 不保存页面正文,--server-response 打印服务器响应头。它适合核对资源存在性,但服务可能对 HEAD 与 GET 使用不同逻辑,结果仍要结合实际客户端行为。
一次性容器里,临时服务只绑定 127.0.0.1:18080。实际输出包含:
curl_index code=200 remote=127.0.0.1:18080 local=127.0.0.1:38312 type=text/html
curl_missing code=404
HTTP/1.0 200 OK
Content-Length: 163200 证明首页资源可用;404 证明另一个路径不存在,但同样证明 TCP 与 HTTP 服务已经响应。结束时后台服务被停止,ss 不再显示 18080 与 19090,实验目录也已删除。
nc 适合在隔离回环或明确获准端点做最小 TCP 验证:
nc -vz 127.0.0.1 18080
printf 'GET / HTTP/1.0\r\n\r\n' | nc -N 127.0.0.1 18080第一条只验证能否建立 TCP;第二条手工发送最小 HTTP 请求,帮助区分“端口打开”与“协议能对话”。不要把 nc 变成未经授权的地址或端口扫描器,也不要把临时监听绑定到非回环接口。
现代发行版常让网络管理器持有运行状态,而不是靠启动脚本按顺序执行若干 ip 命令。常见组件职责如下:
三点边界很容易被忽略。
第一,系统使用 systemd 作为初始化系统,不代表 networkd 或 resolved 一定启用。第二,NetworkManager 可以把每链路 DNS 交给 resolved,它们不是非此即彼。第三,同一个接口最好只有一个管理器负责地址与路由;若 NetworkManager 与 networkd 同时匹配,重连时可能互相覆盖状态。
修改配置前先确认所有者:
systemctl is-active NetworkManager systemd-networkd systemd-resolved
nmcli device status
networkctl status
readlink -f /etc/resolv.conf容器、精简系统、桌面发行版与服务器发行版的默认选择不同。正文中的 ip 命令用于观察内核最终状态;长期配置应进入实际启用的管理器,然后重新激活并用 ip、getent 读回。不要在未确认持有者时同时编辑多个配置入口。
SSH 解决的是加密远程会话,但“加密”不等于“连接对象已经可信”。建立连接时至少有两层身份验证:
首次连接出现未知主机提示时,安全动作不是机械输入 yes,而是从受信渠道获得主机密钥指纹并比对:
ssh-keygen -lf host_ed25519_key.pub
ssh -vv user@host-vv 适合观察配置匹配、地址尝试、密钥交换和认证方法,但日志可能包含内部主机名、用户名与公钥指纹,分享前同样要脱敏。
已记录的主机密钥突然变化,可能来自系统重装、实例替换、负载均衡后端变化,也可能是攻击。应先向负责方核对新旧指纹和变更记录。只有确认变更合法后,才使用精确的 ssh-keygen -R 主机名 更新对应项;直接删除整个 known_hosts 会丢掉其他主机的信任记录。
公钥认证还要区分私钥与公钥:私钥留在受控客户端并设置严格权限,公钥放入服务端允许列表。启用 agent forwarding 会让远端进程间接请求代理签名,受到攻陷的跳板可能滥用代理能力;优先考虑 ProxyJump,并只在确有需要时转发 agent。

端口转发的方向。
ssh -L 127.0.0.1:8080:db.internal:80 jump:在客户端侧监听 127.0.0.1:8080,经 SSH 通道让远端侧连接 db.internal:80。ssh -R 127.0.0.1:9000:127.0.0.1:3000 server:在服务端侧申请监听,再把连接转回客户端侧目标;服务端配置会限制可绑定地址。ssh -D 127.0.0.1:1080 jump:在客户端侧创建 SOCKS 代理入口。显式绑定 127.0.0.1 能避免转发端口意外暴露到所有接口。转发只解决通道与可达性,不会自动为被转发的应用增加授权。
三个工具都可以借助 SSH,但交互模型和同步语义不同。
常见形式:
scp report.csv user@host:/srv/inbox/
sftp user@host
rsync -a --info=progress2 src/ user@host:/srv/archive/rsync 的源尾斜杠尤其重要:
rsync -a src host:/dest/ # 复制 src 目录本身,结果常为 /dest/src/...
rsync -a src/ host:/dest/ # 复制 src 里面的内容到 /dest/...--delete 会删除接收端中源端没有的项目,适合精确镜像,也可能造成真实数据损失。先运行:
rsync -anv --delete src/ user@host:/srv/archive/-n 是 dry run,配合详细输出审阅将新增、更新和删除哪些路径。确认方向、尾斜杠、排除规则和备份后再去掉 -n。传输成功还不等于交付完成;重要文件应校验大小、哈希、权限和目标应用能否读取。
旧脚本和历史文档里常见 ifconfig、route、arp、netstat。它们不必从知识中抹掉,但现代 Linux 排障主线应使用 iproute2:
不能机械做字符串替换。ifconfig 的输出字段与 ip 不同,netstat 和 ss 的过滤语法也不同。迁移脚本时应先写清脚本真正依赖的列,再用显式格式、JSON(工具支持时)或稳定接口解析;不要对面向人的默认输出按空格位置硬切。
遇到只有旧工具的精简环境,可以用它们获取线索,并在记录中写明版本和限制。若 netstat 解析服务名导致卡顿,使用数字显示;现代命令中对应 ss -n。工具选择不改变证据边界:端口监听仍不等于应用健康,路由存在仍不等于目标可达。
面对“访问 service.example:8443 失败”,可以沿下面的顺序推进。每一步都保留时间、命令、关键输出和判断。
先运行 ip -br link 和 ip -s link show dev 接口。确认接口存在、管理状态和较低层状态符合预期,并观察重试期间错误或丢弃计数是否增长。这里解决的是链路前提。
用 ip -br addr 核对预期 IPv4/IPv6 地址、前缀与作用域。如果地址来自 DHCP 或自动配置,再到实际网络管理器查看租约或连接状态,不要先改静态文件。
先对解析出的具体地址运行 ip route get 地址,确认源地址、接口和下一跳。若下一跳同链路,再结合 ip neigh 查看邻居状态。route get 成功后仍要保留“没有发包”的限制。
一次性容器的闭环实操遵循同一顺序:ip link/addr/route/neigh 建立下层快照;getent 通过 files dns 找到 127.0.0.77;python3 只在 127.0.0.1:18080 监听;ss 确认 LISTEN;curl 分别得到 200 和 404;另一个回环端口建立 ESTAB 四元组。结束后停止全部后台进程,再次运行 ss 不见两个临时端口,/tmp/welearn-ch16 已删除,--rm 容器列表为空。
这套顺序的核心不是多敲命令,而是控制变量。先证明下层,再进入上层;发现第一个断点就停下来解释;修复后从断点向下复核,再把完整请求跑一遍。最终记录应能让另一位读者看出:故障发生在哪一层,证据是什么,为什么排除了其他层,以及清理和回滚是否完成。当证据指向某个配置文件、密钥或日志时,接下来的任务就从网络观察切换为在目录树中精确找到对应文件,并核对它的时间、权限和内容。
使用 getent ahosts service.example 查看普通应用会得到哪些地址,并分别固定 IPv4/IPv6 复测。若直接 IP 成功而名称失败,检查 NSS、hosts、resolv.conf 的归属和 resolved 状态。
服务端用 ss -lntp '( sport = :8443 )' 核对绑定地址和进程;客户端只对获准端点做单点连接。连接拒绝、超时和成功是三种不同证据,不能合并成“端口不通”。
最后用 curl -v --connect-timeout 3 --max-time 10 https://service.example:8443/health 检查 TLS、状态码和正文。若返回 401、403、404 或 500,网络链路已经提供了大量正向证据,后续应进入认证、路由或应用日志。