Old-School Networking / 2026 ・ No.01

古法网络入门

第1讲 全景图 ── 从按下申请按钮到送达服务器,用七层来看

发布

Wireshark 的界面。上方列表排着 14 个数据包(ARP 2 个、DNS 2 个、TCP、HTTP 的 POST /api/expenses 和 201 Created 等),选中的是第 8 个 POST。左下方 Frame、Ethernet II、Internet Protocol Version 4、Transmission Control Protocol、Hypertext Transfer Protocol、JavaScript Object Notation 逐行叠在一起,右下方是十六进制的字节
用 Wireshark 打开一次申请。左下方可以看到各层一层层往上叠(在笔者于云端搭建的练习用网络中,于 2026 年 10 月 24 日记录的抓包文件,用 Wireshark 4.2.2 打开后截图。Wireshark 界面保持英文。窗口上方的标题栏是为了说明而后加的)

前端篇之后,是网络。作为进入后端之前的桥梁,我们用 12 讲依次来看程序员应该知道的网络基础。
主线只有一条:追踪报销系统里“提交申请”按钮发出的一次通信,每一讲往下潜一层。
第 1 讲是全景图。把 OSI 参考模型的七层和 TCP/IP 的四层画成地图,再实际抓住一次申请,按层把它拆开来看。

一

申请按钮的另一头

新井前辈,前端 15 讲我毕业了!接下来终于是服务器那边了吧。

古井在那之前问你一句。第 10 讲写的 fetch('/api/expenses'),它是怎么到达服务器的?

新井呃……写了 fetch,就到了。

古井能到的时候这样就行。哪天到不了了,你能说出卡在哪儿吗?网线、Wi-Fi、域名、端口,还是服务器?

新井……问 AI。

古井就算问 AI,决定查哪里的也是你。所以这次,我们把那一次通信从头追到尾。

在前端篇第 10 讲里,申请表单已经能用 fetch 把申请发给服务器,并收到受理编号。从页面这边看,只有一行。但这一行下面,查名字、找对方设备、建立连接、把数据分成小块运送,好几项工作同时在动。本系列就按层来看这些工作。

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

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层 实战
  • 掌握全景 ── OSI 参考模型的七层,和实际在运行的 TCP/IP 四层。每一层有什么设备、什么协议
  • 从下往上潜 ── 从第 2 讲的物理层(网线、电波),到第 10 讲的 HTTP
  • 在手边用起来 ── 第 11 讲是 Docker 和云上的网络,第 12 讲是“连不上”时的排查
  • 每讲都实际测量 ── 在练习用网络里记录真实的数据包,用这些数字来讲解
二

网络是什么

一句话说,网络就是把计算机连起来、把数据送到的机制。从新井的电脑到服务器的路线,粗略画出来是这样的。

从申请按钮到服务器的路线(粗略)

新井的电脑 浏览器 交换机 Wi-Fi 热点 路由器 服务器 Node.js 互联网 提交申请 /api/expenses 家里、公司里的网络(局域网) 网与网相连 服务器一侧 途中的设备把数据当作“小包(数据包)”一站一站地传下去

家里或公司里的网络叫局域网(LAN,Local Area Network)。局域网的出口有路由器,再往外是运营商(ISP)的网络,再连到别的网络……这张由网络组成的网络就是互联网。服务器也待在数据中心的局域网里。

途中的设备不会把数据一口气整个送过去,而是分成叫数据包(packet)的小包裹,一台传给下一台。它不像电话那样和对方之间占住一条专线,而是像邮寄那样,每个包裹写上地址,走空着的路。一条线可以让许多通信共用,没有浪费。

为了让发送方和接收方用同样的方式解读,人们约定了数据的格式和步骤,这就是协议(protocol)。HTTP、TCP、IP、Ethernet,都是协议的名字。

POINT

网络由“连接的线路”“送达的步骤”和“约定(协议)”组成。数据分成小包裹(数据包),一台设备一台设备地接力运送。

三

分层来想

送达之前要做的事情很多,所以网络把工作分成层来考虑。想想寄信的时候。

邮寄的比喻。内容、收件人、地址、运输的车,各是不同人的工作

卡车 地址 收件人“财务部” 信纸 {"title":…} 道路=物理层(网线、电波) 数据链路层 到下一台设备的地址(MAC 地址) 网络层 最终的目的地(IP 地址) 传输层 交给哪个程序(端口 3000) 应用层 内容(HTTP 请求和 JSON)

信纸上写什么,是写信人的事。信封上的“财务部 收”决定在楼里交给谁。地址决定送到哪栋楼。卡车只看地址,把信运到下一个邮局,不读信的内容。道路也不知道卡车装着什么。

网络也一样,每一层各有分工。这样做有三个好处。

  • 可以替换 ── 有线换成 Wi-Fi,HTTP 的写法也不变。下层换掉,上层照常运行
  • 只想自己这一层 ── 写 fetch 的时候,没人会去操心网线的电压
  • 能缩小故障范围 ── “域名查到了,但连不上”,那就查域名那一层以下(第 12 讲)

新井和前端的“HTML 是骨架、CSS 是衣服、JavaScript 是肌肉”很像啊。按职责分开。

古井没错。分开了,坏在哪儿就只修哪儿。古法的匠人,不会把所有东西塞进一个箱子。

四

OSI 参考模型的七层

分层方法里最有名的一把“尺子”,是 OSI 参考模型。国际标准化组织(ISO)从 1977 年开始制定,1984 年以 ISO 7498 发布。它把通信的工作分成七层。

OSI 参考模型的七层。越往下越接近机器,越往上越接近应用

层 名称 一句话 数据的叫法 7 应用层 应用之间的约定(HTTP、DNS) 数据 6 表示层 表示方式(字符编码、加密) 数据 5 会话层 对话的开始与结束 数据 4 传输层 交给哪个程序(端口) 段 3 网络层 送到远方的对方(IP 地址) 包 2 数据链路层 送到相邻的设备(MAC) 帧 1 物理层 把 0 和 1 变成电、光、电波 比特

发送时从上层往下层传,接收时从下往上传。每一层都有主要的设备和协议。整理成一张表是这样的(详细内容见各讲)。

层主要设备主要协议、标准本系列
7 应用层服务器、电脑(上的应用)、代理、七层负载均衡、WAFHTTP、DNS、SMTP、SSH、DHCP第 9、10 讲
6 表示层(没有专用设备)字符编码(UTF-8)、压缩、TLS 的加密第 8 讲
5 会话层(没有专用设备)TLS 的会话(老的有 NetBIOS 等)第 8 讲
4 传输层防火墙、四层负载均衡TCP、UDP、QUIC第 6、7 讲
3 网络层路由器、三层交换机IPv4、IPv6、ICMP第 4、5 讲
2 数据链路层交换机(二层交换机)、Wi-Fi 接入点、网卡Ethernet、Wi-Fi(IEEE 802.11)、ARP、VLAN第 3 讲
1 物理层网线、光纤、连接器、中继器、集线器1000BASE-T 等标准、无线电的标准第 2 讲

数据的叫法也按层不同。第 4 层叫段(segment),第 3 层叫包(packet),第 2 层叫帧(frame),第 1 层叫比特(bit)。平时常常统称“数据包”,但讨论分层时分开叫,就不会混乱。

新井七个都要背啊……

古井从上往下念:“应、表、会、传、网、数、物”。应用、表示、会话、传输、网络、数据链路、物理。

新井听着像一句咒语。

古井背熟了就是护身符。网络出问题时,从“物”往上一层层查。

五

TCP/IP 的四层

不过,现在互联网上实际在运行的不是 OSI 的协议,而是 TCP/IP。TCP/IP 由 Vint Cerf 和 Bob Kahn 在 1974 年的论文中提出雏形,1983 年 1 月 1 日,当时的 ARPANET 统一切换到了 TCP/IP。1980 年代末到 1990 年代初,人们曾为 OSI 和 TCP/IP 谁会普及而争论不休(被称为“协议战争”,Protocol Wars),最后普及的是 TCP/IP。

TCP/IP 的思路在 1989 年的 RFC 1122 中整理成了四层。和 OSI 这把尺子并排放,是这样的。

OSI 是“尺子”,TCP/IP 是“实物”

OSI 参考模型(尺子) TCP/IP(实物) 主要协议 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层 应用层 HTTP DNS TLS 第5、6层的工作也在这里 传输层 TCP UDP 网际层 IP ICMP 链路层 Ethernet Wi-Fi + 网线、电波 “二层交换机”“七层负载均衡”里的数字,就是 OSI 的层号

主要的区别有两个。第一,相当于 OSI 第 5、6 层的工作,在 TCP/IP 里合并在应用层。加密用的 TLS、字符编码,都是应用和程序库的事。第二,OSI 的第 1、2 层在 TCP/IP 里合并成一个链路层。

尽管如此,OSI 的层号仍是现场每天都在用的词。“二层交换机”“三层交换机”“四层负载均衡”“在七层分流”里的数字,都是 OSI 的层号。本系列也按内容讲 TCP/IP,编号用 OSI 的方式来进行。

POINT

OSI 参考模型是用来称呼各层的尺子。实际在运行的是 TCP/IP 的四层。第 5、6 层几乎看不到独立的身影,藏在应用和 TLS 里。

六

抓住一次申请

地图有了,来看实物。我在云端的 Linux 上,用叫网络命名空间(network namespace)的机制,搭了一个三台机器的小网络(做法在第 11 讲详细讲)。

角色IP 地址MAC 地址做什么
新井的电脑10.0.1.1002:00:00:00:01:10发送申请
路由器(电脑一侧)10.0.1.102:00:00:00:01:01转发。也负责告诉名字(DNS)
路由器(服务器一侧)10.0.2.102:00:00:00:02:01转发
服务器10.0.2.2002:00:00:00:02:20用 Node.js 接收 /api/expenses

服务器的名字定为 api.keihi.example(.example 是为举例说明而保留的名字)。在电脑一侧和服务器一侧都开着 tcpdump 记录,然后发送一次申请。这里用 curl 代替浏览器,发送的内容也比第 10 讲的表单小,只是一个 JSON。

# 在新井的电脑(10.0.1.10)上,用 curl 重现和申请相同的发送
$ curl -X POST -H 'Content-Type: application/json' \
    --data-binary '{"title":"ニューヨーク出張","total":46851}' \
    http://api.keihi.example:3000/api/expenses
{"id":"EXP-2026-0012","status":"submitted"}
# 收到了受理编号(HTTP 状态是 201 Created)

受理编号 EXP-2026-0012 回来了。这时在新井的电脑上流过的数据包,一共 14 个。

# 在新井的电脑上记录的一次申请的全部内容(编号、经过时间、发送方、接收方、种类、字节数、内容)
# ① ARP:向所有人询问路由器(10.0.1.1)的 MAC 地址
 1   0.000ms  02:00:00:00:01:10 -> broadcast         ARP   42  Who has 10.0.1.1? Tell 10.0.1.10
 2   0.012ms  02:00:00:00:01:01 -> 02:00:00:00:01:10 ARP   42  10.0.1.1 is at 02:00:00:00:01:01
# ② DNS:向路由器的 DNS 询问 api.keihi.example 的 IP 地址
 3   0.014ms  10.0.1.10         -> 10.0.1.1          DNS   77  query A api.keihi.example
 4   0.350ms  10.0.1.1          -> 10.0.1.10         DNS   93  response A api.keihi.example A 10.0.2.20
# ③ TCP:与服务器的 3000 端口建立连接(三次往来)
 5   0.680ms  10.0.1.10         -> 10.0.2.20         TCP   74  49914 -> 3000 [SYN] Seq=0
 6   0.808ms  10.0.2.20         -> 10.0.1.10         TCP   74  3000 -> 49914 [SYN, ACK] Seq=0 Ack=1
 7   0.818ms  10.0.1.10         -> 10.0.2.20         TCP   66  49914 -> 3000 [ACK] Seq=1 Ack=1
# ④ HTTP:发送申请,收到受理编号
 8   0.891ms  10.0.1.10         -> 10.0.2.20         HTTP 266  POST /api/expenses HTTP/1.1 + JSON
 9   0.898ms  10.0.2.20         -> 10.0.1.10         TCP   66  3000 -> 49914 [ACK] Seq=1 Ack=201
10   7.011ms  10.0.2.20         -> 10.0.1.10         HTTP 269  HTTP/1.1 201 Created + JSON
11   7.033ms  10.0.1.10         -> 10.0.2.20         TCP   66  49914 -> 3000 [ACK] Seq=201 Ack=204
# ⑤ TCP:关闭连接
12   7.206ms  10.0.1.10         -> 10.0.2.20         TCP   66  49914 -> 3000 [FIN, ACK] Seq=201 Ack=204
13   8.472ms  10.0.2.20         -> 10.0.1.10         TCP   66  3000 -> 49914 [FIN, ACK] Seq=204 Ack=202
14   8.479ms  10.0.1.10         -> 10.0.2.20         TCP   66  49914 -> 3000 [ACK] Seq=202 Ack=205

14 个数据包的顺序。左边的编号就是上面记录里的 No.

新井的电脑 路由器 服务器 10.0.1.1 的 MAC 是? 1 是 02:00:00:00:01:01 2 api.keihi.example 是? 3 是 10.0.2.20 4 SYN 5 SYN, ACK 6 ACK 7 POST /api/expenses 8 ACK 9 201 Created 10 ACK 11 FIN, ACK 12 FIN, ACK 13 ACK 14 ARP 第3讲 DNS 第9讲 连接 第6讲 HTTP 第10讲 断开 第6讲

在发出申请(第 8 个)之前,已经来回了 7 个。先向所有人询问路由器的 MAC 地址(ARP),再用服务器的名字查 IP 地址(DNS),然后和服务器建立连接(TCP 的三次往来),这才是正题 POST。收到受理编号后,关闭连接。每一项都是本系列某一讲的主角。

实测(电脑一侧)数值
数据包个数14 个(ARP 2、DNS 2、TCP 连接 3、HTTP 与确认 4、断开 3)
流过的字节总数1,333 字节
其中正题(申请的 JSON 50 + 回复的 JSON 43)93 字节(约 7%)
从第一个 ARP 到最后的确认8.479 毫秒(同一台机器里的练习网络,所以非常快)

新井正题才 93 字节,总共却有 1,333 字节……剩下的是什么?

古井是信封、收件人和运单。下一章,拆开一个看看。

七

信封里套信封

第 8 个数据包(申请本身)是 266 字节。在 Wireshark 里逐层选中,该层负责的字节就会变蓝。

把同一个数据包的字节显示四次,只把所选层的部分涂成蓝色。① Ethernet II 是开头的 14 字节,② IPv4 是接下来的 20 字节,③ TCP 是再接下来的 32 字节,④ HTTP 是后面文字部分的 150 字节
逐层选中,只有该层负责的字节会变蓝。从开头起,外层的头部依次排列。HTTP 后面的 50 字节是 JSON 正文(在笔者于云端搭建的练习用网络中,于 2026 年 10 月 24 日记录的抓包文件,用 Wireshark 4.2.2 打开后截图。Wireshark 界面保持英文。窗口上方的标题栏是为了说明而后加的)

从开头起,依次是 Ethernet、IP、TCP 的标头(头部,header),后面接着 HTTP 的文字和 JSON 正文。按层分开写出来是这样的。

# ① Ethernet II(14 字节)
#   目的 MAC 02:00:00:00:01:01(路由器)、源 MAC、类型 08 00(里面是 IPv4)
02 00 00 00 01 01 02 00 00 00 01 10 08 00
# ② IPv4(20 字节)
#   第 9 字节 40=TTL 64,第 10 字节 06=里面是 TCP,
#   0a 00 01 0a=源 10.0.1.10,0a 00 02 14=目的 10.0.2.20
45 00 00 fc 1b f8 40 00 40 06
06 e7 0a 00 01 0a 0a 00 02 14
# ③ TCP(32 字节)
#   c2 fa=源端口 49914,0b b8=目的端口 3000,
#   后面是序号、确认号、标志等
c2 fa 0b b8 83 5b 4e 23 ab f5 ef c6 80 18 00 3f
18 0c 00 00 01 01 08 0a b7 e2 b8 5b 9f a1 af c2
# ④ HTTP(150 字节)
#   从这里开始是文字。行尾是 0d 0a(\r\n),空行表示头部结束
POST /api/expenses HTTP/1.1
Host: api.keihi.example:3000
User-Agent: curl/8.5.0
Accept: */*
Content-Type: application/json
Content-Length: 50

# ⑤ JSON(50 字节)
#   申请的内容。日文用 UTF-8,每个字 3 字节
{"title":"ニューヨーク出張","total":46851}

266 字节的构成。越外层,越是把里面整个当作“内容”来运送

14 Ethernet 20 IP 32 TCP 150 HTTP 50 JSON 应用数据 200 字节 TCP 段 232 字节 IP 包 252 字节 Ethernet 帧 266 字节

发送一方从上层开始,每层把自己的头部加在前面再交给下层。HTTP 做出的 200 字节,TCP 加上 32 字节的头部成为 232 字节,IP 再加 20 字节成为 252 字节,Ethernet 加 14 字节成为 266 字节。这叫封装。接收一方正好相反,从下层开始读取并剥掉头部,把内容往上交。

每一层都只读自己的头部。IP 不读 TCP 的头部,TCP 不读 HTTP 的文字。所以各层才能替换。

POINT

封装=信封里套信封。下层把上层的数据整个当作“内容”运送,只在前面加上自己的头部。这次的申请,50 字节的正题前面,一共加了 216 字节的头部。

另外,Wireshark 里看到的 266 字节,不包括在网线上前后附加的部分(8 字节的同步信号,以及检查是否损坏的 4 字节)。这些留到第 2、3 讲再看。

八

越过路由器之后

同一次申请的数据包,我在路由器之前(新井的电脑一侧)和之后(服务器一侧)两处都做了记录。并排看看。

把同一次申请的数据包,在新井的电脑一侧和服务器一侧两处记录后并排。Ethernet 的目的和源 MAC 地址、IP 的 Time to Live(64 和 63)、Header Checksum(0x06e7 和 0x07e7)用红框圈出,源和目的 IP 地址(10.0.1.10 和 10.0.2.20)用蓝框圈出
在路由器前后比较同一个数据包。MAC 地址整个换掉,TTL 减 1,IP 地址不变(在笔者于云端搭建的练习用网络中,于 2026 年 10 月 24 日记录的抓包文件,用 Wireshark 4.2.2 打开后截图。Wireshark 界面保持英文。窗口上方的标题栏是为了说明而后加的)
项目电脑一侧服务器一侧
目的 MAC02:00:00:00:01:0102:00:00:00:02:20
源 MAC02:00:00:00:01:1002:00:00:00:02:01
TTL(还能转发几次)6463
IP 校验和0x06e70x07e7
源 IP → 目的 IP10.0.1.10 → 10.0.2.20相同
端口、HTTP、JSON、总长度49914 → 3000,266 字节相同

MAC 地址前后两个整个换掉了。电脑一侧是“从电脑到路由器”,服务器一侧是“从路由器到服务器”。因为 MAC 地址是到相邻设备的地址。而 IP 地址从头到尾都不变,它是最终的目的地。用邮寄来比喻,就像卡车在每个邮局换乘,信封上的地址却不改写。

TTL 是每经过一台路由器就减 1 的数。变成 0 的数据包会被丢弃,所以迷路的数据包不会永远转下去(第 5 讲的 traceroute 就利用了这个机制)。因为 TTL 变了,IP 头部的校验用数字(校验和)也重新计算了。

设备看内容看到哪一层

1 物理层 2 数据链路层 3 网络层 4 传输层 5 会话层 6 表示层 7 应用层 新井的电脑 1 物理层 2 数据链路层 交换机 1 物理层 2 数据链路层 3 网络层 路由器 1 物理层 2 数据链路层 3 网络层 4 传输层 5 会话层 6 表示层 7 应用层 服务器

不同设备拆开信封的深度不同。交换机看到第 2 层的 MAC 地址,决定从哪个口送出去。路由器看到第 3 层的 IP 地址,决定下一站交给谁,然后换上新的第 2 层再送出去。读 TCP 和 HTTP 的,只有两端的电脑和服务器(也有像防火墙、负载均衡那样,特意往上层看的设备)。

新井我还以为路由器会把内容全部读一遍。

古井它只看到地址为止。所以里面是 JSON 还是视频,都能用同样的速度运送。代价是,保护内容成了两端的工作。那是第 8 讲 TLS 的话题。

九

备好工具

本系列每一讲都用这样的工具来确认。都能在平时的电脑上马上用。

想查什么MacWindowsLinux讲
自己的 IP、MAC 地址ifconfigipconfig /allip addr3、4
能否到达对方pingpingping5
途中的路径traceroutetracerttraceroute5
正在用的端口lsof -inetstat -anoss -tan6、7
从名字查 IP 地址dignslookupdig9
HTTP 的往来curl -vcurl.exe -vcurl -v10
数据包本身Wireshark(在界面上看)、tcpdump(记录)每讲

Wireshark 免费,Windows、Mac、Linux 都能用(写作时的最新版是 2026 年 9 月 23 日的 4.6.9,本文的截图是 Ubuntu 的 4.2.2)。打开这次的记录文件,逐层选中,应该能看到和第七章照片一样的样子。

NOTE

抓包请在自己管理的网络里进行。在公司或学校的网络中,可能会看到别人的通信,一定要先取得管理员的许可。

结 — 一页总结与下一讲

  1. 网络把数据分成数据包,一台设备一台设备地接力运送。解读的约定就是协议。
  2. 工作分成层。换掉下层,上层不变,故障位置也能缩小。
  3. OSI 参考模型是七层的尺子(应、表、会、传、网、数、物)。实际运行的是 TCP/IP 的四层。
  4. 一次申请,电脑上流过 14 个数据包(ARP、DNS、TCP、HTTP、断开),共 1,333 字节。正题是 93 字节。
  5. 申请的数据包 266 字节 = Ethernet 14、IP 20、TCP 32、HTTP 150、JSON 50。这就是封装。
  6. 越过路由器后,MAC 被换掉,IP 不变,TTL 减 1。
  7. 交换机看到第 2 层,路由器看到第 3 层。读 TCP 和 HTTP 的只有两端。

新井下一讲是物理层吧。网线不就是插上就完事了吗?

古井插上就能用,是因为机器一丝不苟地遵守着某人定下的约定。那 266 字节在网线上是什么模样,我们去看看。

参考

记录来自笔者在云端 Linux(Ubuntu 24.04)上用网络命名空间搭建的练习用网络(电脑、兼做 DNS(dnsmasq)的路由器、服务器(Node.js)),于 2026 年 10 月 24 日用 tcpdump 抓取。发送用的是 curl 8.5.0,界面是 Wireshark 4.2.2,表里的数字都是从这份记录读出的实际数值。MAC 地址是为了易读而手动设定的值(以 02 开头的本地用地址)。这个练习用网络没有使用 IPv6(IPv6 在第 4 讲讨论)。登场人物均为虚构。

古法网络入门 第1讲 — 全景图 / 2026.10

← 返回文章列表