Old-School Networking / 2026 ・ No.12

古法网络入门

第12讲(最终讲) 连不上时的排查 ── 从下层开始,一级一级

发布

Wireshark 的界面。在电脑的口上记录的 7 个 ARP。第 1、2 个是解析器 198.51.100.53 的询问与回答。第 3、4、5 个是 Who has 203.0.113.20? Tell 192.168.1.10,在 0.0003 秒、1.006 秒、2.029 秒连续 3 次,没有回答。选中第 5 个,详情的 Address Resolution Protocol (request) 里是 Target MAC address: 00:00:00:00:00:00、Target IP address: 203.0.113.20
申请服务器的机器不在时电脑的口。问了 3 次“203.0.113.20 是谁?”都没有回音,curl 在 3.05 秒时放弃了。错误信息只说“连不上”,看记录就知道卡在第 2 层(在笔者于云端搭建的练习用网络中,于 2026 年 10 月 25 日记录,用 Wireshark 4.2.2 打开后截图。界面保持英文。窗口上方的标题栏和小标题是为了说明而后加的)

“按了申请按钮,什么反应也没有。”最终讲,就从这句话开始调查。
把第 9、10 讲的练习网络,按网线、路、对方的机器、名字、端口、锁、内容,一次故意弄坏一个地方。每次出现的错误信息,以及用什么工具找出卡在哪一层的步骤,都从下层开始依次确认。

一

“什么反应也没有”

新井前辈,财务来电话了,说“按了申请按钮什么反应也没有”。是服务器挂了吗?

古井可能是挂了,也可能是网线掉了,也可能是名字查不到。别一下子跳到答案。

新井那从哪儿开始?

古井从下面开始。用手指把花了 11 讲做出来的地图划一遍。

全 12 讲路线图(当前位置:第 12 讲)

1 全景图 2 物理层 3 数据链路层 4 IP 地址 5 路由器 6 TCP 7 UDP・套接字 8 TLS 9 DNS 10 HTTP 11 开发者的网络 12 故障排查 当前位置 全景图 第1层 第2层 第3层 第4层 第5・6层 第7层 实战
  • 排查的梯子 ── 每层一个问题、一个工具,从下往上
  • 弄坏 7 种 ── 网线、路、对方的机器、名字、端口、锁、nginx 后面。每次的信息和时间(实测)
  • 被拒绝,还是被丢弃 ── 0.041 秒的 RST 和 10 秒的超时(实测与 Wireshark)
  • 慢的时候 ── 用 curl 把时间分成名字、TCP、TLS、服务器(实测)

练习网络和第 9、10 讲相同。电脑和运营商的解析器在线的这一边,DNS 服务器和申请服务器在单程 20 毫秒的捣乱线对面。这次在申请服务器前面还放了 nginx(80 号)。每次只弄坏一个地方,记录后再恢复原样。

二

排查的梯子

排查的第一步和第 11 讲一样,先用一行写下从哪里、发往哪里的几号。这次就是“从电脑,发往 expenses.example 的 3443 号,用 HTTPS”。然后每层问一个问题。

每层一个问题、一个工具

层 要确认的事 工具 内容(HTTP) 回复的状态码,是谁回的 curl -v 锁(TLS) 证书验证通过了吗 openssl s_client 端口(TCP) 是被拒绝,还是被丢弃 nc -vz 名字(DNS) 名字变成地址了吗 dig 地址与路(IP) 有路吗,邻居有回应吗 ip route / ip neigh 线与口 口连着吗 ip link 从下往上一级一级来。通过的那一级以下,就不用再怀疑了 错误信息只说出最上面那一级发生的事(第三章)

梯子要从下往上爬。上面一级架在下面一级上:口没连上就查不到名字,查不到名字 TCP 就开始不了,没有 TCP 就谈不上 TLS 和 HTTP。反过来,某一级通了,就证明它下面全都在工作,不用再怀疑了。

三

别被错误信息骗了

首先,拔掉网线(练习时是把线对面的口关掉)。

# 拔掉网线(把线对面的口关掉)
pc$ curl https://expenses.example:3443/api/expenses
    curl: (6) Could not resolve host: expenses.example   (6.025 s)
# 先看自己的口
pc$ ip -br link show eth0
    eth0   DOWN   <NO-CARRIER,BROADCAST,MULTICAST,UP>
pc$ ping -c2 198.51.100.53
    2 packets transmitted, 0 received, 100% packet loss

curl 的信息是“Could not resolve host”,查不到名字,而且是等了 6.02 秒之后。可是 DNS 什么也没坏。curl 最先要做的是查名字,在那里卡住了,所以才这么写。错误信息只说出最上面发生的事。从梯子下面看,ip link 的 NO-CARRIER(对面没有人)一目了然。

POINT

说“DNS 坏了”之前,先看自己的口,再 ping 一下解析器。Wi-Fi 没连好、网线掉了、VPN 断了,常常会以查名字失败的样子出现。

四

地址与路

接下来是第 3 层。先删掉去往 203.0.113.0/24 的路(路由)。

# 删除去往 203.0.113.0/24 的路(路由)
pc$ curl -v https://expenses.example:3443/api/expenses
    *   Trying 203.0.113.20:3443...
    * Immediate connect fail for 203.0.113.20: Network is unreachable
    curl: (7) Failed to connect … after 0 ms: Couldn't connect to server
pc$ ip route get 203.0.113.20
    RTNETLINK answers: Network is unreachable

没有路,数据包连电脑都出不去。0 毫秒就是“Network is unreachable”。用 ip route get 可以直接问去往那个地址的路有没有。

这次是有路、但对方的机器不在的情况。把申请服务器的地址 203.0.113.20 摘掉。

# 对方的机器不在(摘掉 203.0.113.20)
pc$ curl https://expenses.example:3443/api/expenses
    curl: (7) Failed to connect … after 3053 ms: Couldn't connect to server
# 邻居的地址(MAC)查到了吗
pc$ ip neigh show 203.0.113.20
    203.0.113.20 dev eth0 FAILED
pc$ ping -c3 203.0.113.20
    3 packets transmitted, 0 received, 100% packet loss

curl 等了 3.05 秒,“连不上”。封面照片就是这时电脑的口。用第 3 讲的 ARP 问了 3 次“203.0.113.20 是谁?”,没有回音就结束了。ip neigh 的 FAILED 是“查不到邻居的地址(MAC)”的记录,要怀疑对方的机器停了,或者地址设置错了。

五

名字

名字这一级,用两种方式弄坏:停掉解析器,以及把名字打错。

# ① 解析器停了
pc$ curl https://expenses.example:3443/api/expenses
    curl: (6) Could not resolve host: expenses.example
pc$ dig expenses.example
    ;; communications error to 198.51.100.53#53: connection refused
# ② 名字打错(exmaple)
pc$ curl https://expenses.exmaple:3443/api/expenses
    curl: (6) Could not resolve host: expenses.exmaple
pc$ dig expenses.exmaple
    ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN
# 正确的名字
pc$ dig +short expenses.example
    203.0.113.20

curl 的信息两者都是“Could not resolve host”,分不出来。用 dig 就清楚了。解析器停了是“communications error”(根本拿不到回答),打错是 status: NXDOMAIN(好好地拿到了回答,回答是“没有这个名字”)。前者是第 3 层为止或解析器的问题,后者是名字本身的问题。

POINT

正如第 9 讲所说,dig 不看 hosts。只有应用表现异常时,也用 getent hosts(Mac 用 dscacheutil)查一下,怀疑 hosts 里的旧条目。

六

端口:被拒绝,还是被丢弃

第 4 层最重要的,是区分被拒绝还是被丢弃。比较停掉服务器程序,和让对方防火墙默默丢弃两种情况。

# ① 服务器程序停了(没有人在那个端口等)
pc$ curl https://expenses.example:3443/api/expenses
    curl: (7) Failed to connect … after 41 ms: Couldn't connect to server
pc$ nc -vz expenses.example 3443
    … port 3443 (tcp) failed: Connection refused
srv$ ss -ltn 'sport = :3443'
    (无)
# ② 对方的防火墙默默丢弃(DROP)
pc$ curl --connect-timeout 10 https://expenses.example:3443/api/expenses
    curl: (28) Failed to connect … after 10002 ms: Timeout was reached
pc$ nc -vz -w 3 expenses.example 3443
    … port 3443 (tcp) timed out: Operation now in progress

立刻回来的 RST,和没有回音的 SYN

被拒绝 PC 服务器 被丢弃 PC 服务器 SYN RST 0.041 s 已经到达对方。 Connection refused 防火墙 0.0 × 1.0 × 2.0 × 3.1 × 4.1 × 5.1 × 7.1 × Timeout 10 s 立刻“被拒绝”说明到达了对方。等了半天才“超时”,说明在途中消失了
把两个 Wireshark 数据包列表上下并排。上面,电脑发往 203.0.113.20 的 3443 号的 SYN,在 0.040679 秒收到 RST, ACK。下面,SYN 在 0、1.01、2.03、3.06、4.08、5.11、7.12 秒重发,没有任何回音
上面是停掉服务器程序时,下面是对方防火墙默默丢弃时。同样是“连不上”,上面到达了对方后被拒绝,下面在途中消失了(在笔者于云端搭建的练习用网络中,于 2026 年 10 月 25 日记录,用 Wireshark 4.2.2 打开后截图。界面保持英文。窗口上方的标题栏和小标题是为了说明而后加的)

程序停了,对方的操作系统会用 RST 立刻回答“这个端口没人在等”。0.041 秒正好是捣乱线的一个来回。已经到达对方的机器,所以要看对方的程序在不在运行(ss -ltn),端口对不对。

防火墙丢弃时,什么也不会回来。电脑像第 6 讲看到的那样重发 SYN,curl 在 10 秒后超时。这是在途中某处消失了,要怀疑防火墙、安全组、途中的路。

七

锁

TCP 连上了,也可能卡在 TLS 这一级。不告诉 curl 练习用的 CA,就用 HTTPS 发送。

# 不认识练习用的 CA 就去访问 HTTPS
pc$ curl https://expenses.example:3443/api/expenses
    curl: (60) SSL certificate problem: unable to get local issuer certificate
# 用 openssl 直接看对方出示的证书
pc$ openssl s_client -connect expenses.example:3443 -servername expenses.example
    subject=CN = expenses.example
    issuer=CN = Kiji Practice Root CA
    Verify return code: 21 (unable to verify the first certificate)
# 告诉它 CA 之后
pc$ openssl s_client … -CAfile ca.pem
    Verify return code: 0 (ok)

openssl s_client 是直接查看对方出示的证书的工具。能看到“谁的证书(subject)”“谁签发的(issuer)”和验证结果(Verify return code)。告诉它 CA 就是 0(ok)。第 8 讲的 4 种情形(不认识签发者、名字不对、过期、自签名)在这里分辨。解决办法是告诉它正确的 CA,或者修好证书。用 -k 关掉验证不算修好。

八

内容:5xx 是谁回的

最后一级是 HTTP。在申请服务器前面放 nginx,用两种方式弄坏它后面:忘了启动新版本(/v2/)的应用,以及应用太慢。

# 申请服务器前面有 nginx(80 号)。/v2/ 后面(4000 号)忘了启动
pc$ curl http://expenses.example/api/expenses
    → 200  (0.089 s)
pc$ curl http://expenses.example/v2/api/expenses
    → 502 Bad Gateway  (0.083 s)
pc$ curl 'http://expenses.example/api/report?ms=3000&n=1'
    → 504 Gateway Time-out  (2.085 s)
# nginx 的记录(error.log,节选)
    connect() failed (111: Connection refused) while connecting to upstream,
      upstream: "http://127.0.0.1:4000/api/expenses"
    upstream timed out (110: Connection timed out) while reading response header
      from upstream, upstream: "http://127.0.0.1:3000/api/report?ms=3000&n=1"

返回 5xx 的是前面的 nginx,出问题的是它后面

PC nginx :80 应用 127.0.0.1:3000 v2(忘了启动) 127.0.0.1:4000 要 3 秒 × 502 / 504 返回 5xx 的是电脑眼前的 nginx,出问题的是它后面 502=连不上后面,504=后面没有按时回答 原因写在 nginx 的 error.log 里,附带后面的地址
Wireshark 的界面。用显示过滤器 http 筛选出 6 个。第 4 个 GET /api/expenses 对应第 6 个 200 OK,第 14 个 GET /v2/api/expenses 对应第 16 个 HTTP/1.1 502 Bad Gateway,第 24 个 GET /api/report?ms=3000&n=1 对应第 26 个 HTTP/1.1 504 Gateway Time-out(2.28 秒)。第 16 个的详情里有 Server: nginx/1.24.0 (Ubuntu)、Content-Length: 166
nginx 后面没有运行时的回复。返回 502 的,正如 Server 头部所示,是 nginx,而不是应用(在笔者于云端搭建的练习用网络中,于 2026 年 10 月 25 日记录,用 Wireshark 4.2.2 打开后截图。界面保持英文。窗口上方的标题栏和小标题是为了说明而后加的)

有回复来,就说明下面五级全都通了。要看的是谁回的。502 和 504 都是电脑眼前的 nginx 回的(照片里的 Server: nginx)。502 是“想连后面却被拒绝”,504 是“后面没在 2 秒内回答”。原因写在 nginx 的 error.log 里,附带后面的地址。4xx 是请求方式(第 10 讲),5xx 是服务器一侧,其中 502、504 是“服务器的再后面”。

九

慢的时候

“连不上”的亲戚是“慢”。慢的时候,把时间按级分开。curl 的 -w 会告诉你从开始算起,查名字、TCP、TLS、收到第一个字节的时刻。

# 清掉解析器的记忆后,获取 2 次需 300 毫秒的报告(用 curl -w 分解时间)
pc$ curl -w 'dns %{time_namelookup} tcp %{time_connect} tls %{time_appconnect}
        first-byte %{time_starttransfer} total %{time_total}\n' …
    第 1 次  dns 0.166  tcp 0.206  tls 0.252  first-byte 0.595  total 0.595
    第 2 次  dns 0.002  tcp 0.043  tls 0.090  first-byte 0.434  total 0.434

0.595 秒的明细(实测)

第 1 次 0.166 0.344 0.595 s 第 2 次 0.345 0.434 s 名字(DNS) TCP 握手 TLS 握手 服务器处理 知道时间花在哪里,就知道该看哪一层 这里每次都有约 0.34 秒在服务器一侧。只有第 1 次查名字用了 0.166 秒

取差值,第 1 次是名字 0.166 秒、TCP 握手 0.041 秒、TLS 握手 0.045 秒、服务器处理与回复 0.344 秒。第 2 次名字缩短到 0.002 秒(第 9 讲的缓存)。两次最长的都是服务器一侧约 0.34 秒(300 毫秒处理+一个来回),不是网络的问题。说“网络慢”之前,先看这个分解。

十

速查表与在自己的电脑上

这个连载里实际遇到的错误信息,以及首先要怀疑的那一级。

信息(例)首先怀疑第一步
Could not resolve host名字,但也包括它下面ip link 和 dig
Network is unreachable路(没有路由)ip route get 地址
等了几秒连不上(ARP 没回应)对方的机器、地址设置ip neigh
Connection refused端口(到了,但没人在等)在对方 ss -ltn
Timeout was reached途中被丢弃防火墙、nc -vz
SSL certificate problem锁(第 8 讲的 4 种情形)openssl s_client
502 / 504前面服务器的再后面前面的 error.log
CORS 错误浏览器的守门人(第 10、11 讲)API 返回的头部
ECONNREFUSED 127.0.0.1弄错了 localhost(第 11 讲)从哪里发的

梯子上的工具,在不同操作系统里名字略有不同。

级MacWindowsLinux
线与口ifconfigipconfig /allip -br link
路netstat -rnroute printip route get 地址
邻居arp -aarp -aip neigh
名字dig 名字Resolve-DnsName 名字dig 名字
端口nc -vz 名字 端口Test-NetConnection 名字 -Port 端口nc -vz 名字 端口
锁与内容curl -v https://名字/

结 — 全 12 讲一页总结

从下到上追踪申请按钮一次通信的 12 讲

12 排查 从下往上,一级一级 11 开发者的电脑 localhost、Docker、代理 10 HTTP 申请的内容。状态码和头部 9 DNS 从名字查地址 8 TLS(第 5、6 层) 上锁并确认对方 6・7 TCP・UDP 按端口分发、重发 4・5 IP・路由器 地址和选路 2・3 物理・数据链路 电信号与电波,邻居之间的地址 申请从下往上 第 1 讲的全景图里,装进了 11 讲的内容
  1. 先写一行:从哪里、发往哪里的几号。
  2. 梯子从下往上。通过的那一级以下不再怀疑。
  3. 错误信息只说出最上面发生的事。网线掉了也会是“Could not resolve host”。
  4. 被拒绝(立刻)说明到达了对方,超时(要等)说明在途中消失了。
  5. 名字用 dig 查,分清停了的解析器和 NXDOMAIN。
  6. 锁用 openssl s_client 查,不关验证地修好。
  7. 5xx 要看是谁回的。慢的时候按级分解时间。

新井财务那件事,从 ip link 开始依次看,原来是无线切换时断了线。服务器好好的。

古井干得漂亮。有了 12 讲的地图,卡在哪里都不会迷路。

新井接下来,我想了解接收这个申请的服务器内部。

古井好啊。网络之旅就到这里。接下来,到服务器里面去吧。

参考

记录来自笔者在云端 Linux(Ubuntu 24.04,内核 6.18)上用网络命名空间搭建的练习网络,于 2026 年 10 月 25 日抓取。构成与第 9、10 讲相同(解析器 Unbound 1.19.2,DNS 服务器 NSD 4.8.0,申请服务器 Node.js 22.23),在申请服务器前面放了 nginx 1.24.0,电脑一侧是 curl 8.5.0 和 OpenSSL 3.0。名字和地址都是为说明而保留的或为练习而制作的。电脑和服务器之间是第 6 讲的捣乱线(单程 20 毫秒)。表中的数字和输出都是从这些记录和当时命令的输出读出的实际数值(较长的输出省略了一部分)。登场人物均为虚构。感谢您读完全部 12 讲。

古法网络入门 第12讲 — 连不上时的排查 / 2026.10

← 返回文章列表