<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>OSI 模型 on 张欣耕的个人博客</title><link>https://www.shanechang.com/zh-cn/tags/osi-%E6%A8%A1%E5%9E%8B/</link><description>Recent content in OSI 模型 on 张欣耕的个人博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Wed, 13 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://www.shanechang.com/zh-cn/tags/osi-%E6%A8%A1%E5%9E%8B/index.xml" rel="self" type="application/rss+xml"/><item><title>买烤面包机的艺术</title><link>https://www.shanechang.com/zh-cn/p/networking-journey-buying-a-toaster/</link><pubDate>Wed, 13 May 2026 00:00:00 +0000</pubDate><guid>https://www.shanechang.com/zh-cn/p/networking-journey-buying-a-toaster/</guid><description>&lt;img src="https://www.shanechang.com/p/networking-journey-buying-a-toaster/cover.webp" alt="Featured image of post 买烤面包机的艺术" /&gt;&lt;p&gt;如果你是新读者:在上一篇&lt;a class="link" href="../networking-journey-portainer-and-switches/" &gt;交换机到底在干嘛&lt;/a&gt;
里,我承认自己在网络这事上&amp;quot;嘴上有功底&amp;quot;,然后认真补课,终于理解了:为什么一个监听在 127.0.0.1 的服务,会对那个通过 10.88.0.1 过来的容器完全隐身。&lt;/p&gt;
&lt;p&gt;对老朋友们:这篇是一次有意为之的小小&amp;quot;岔路&amp;quot;。&lt;/p&gt;
&lt;h2 id="小尴尬"&gt;小尴尬
&lt;/h2&gt;
&lt;p&gt;写第一篇的中途,我试图把新学的东西讲给一个不写代码的朋友听。晚餐时她礼貌地问:你这周在发什么技术疯?&lt;/p&gt;
&lt;p&gt;我说了大概三句话,她的眼睛就开始出现那种神奇的微光。&lt;/p&gt;
&lt;p&gt;你懂的——那种&amp;quot;我爱你我在场,但我已经听不懂中文了&amp;quot;的微光。我已经说出了 TCP, 内核, bridge interface,下一步就要爆出 MAC address,幸好我及时刹车。&lt;/p&gt;
&lt;p&gt;这时我发现一个问题:我现在会解释交换机了;我能解释虚拟桥;我能解释为什么 Portainer 容器看不见我的 SSH 隧道。可如果她问我——从她在网站上点下&amp;quot;购买&amp;quot;的那一刻起,到页面回个&amp;quot;下单成功&amp;quot;为止,整件事到底一秒不落地发生了什么? ——我会直接开摆。我有很多零件,但没有一个完整的故事。&lt;/p&gt;
&lt;p&gt;于是我决定写一个。一个真的故事。有角色,有场景,有戏剧冲突。尽量不说术语。甚至要做到能在餐桌上讲完的那种。&lt;/p&gt;
&lt;p&gt;&amp;ldquo;解码环&amp;rdquo;(每个角色在计算机世界里到底是谁)在文末。请先看故事。尤其是你从没认真想过网站&amp;quot;到底怎么工作&amp;quot;的话,更要先看。&lt;/p&gt;
&lt;h2 id="出场人物"&gt;出场人物
&lt;/h2&gt;
&lt;p&gt;先认识一下小小的演员表,他们出场快,退场也快。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Jack。一个在家网购的男人。他只想买台烤面包机。这就是他全部的人设。&lt;/li&gt;
&lt;li&gt;浏览器小助手(Browser-Bot)。住在 Jack 的笔记本里。写便条, 打包包裹, 交给快递。忠诚, 龟毛。&lt;/li&gt;
&lt;li&gt;信使之海(The Sea of Couriers)。一整片在 Jack 家和商店之间的接力快递大军。每个人只知道&amp;quot;下一个该交给谁&amp;quot;。他们不看信,只转运。&lt;/li&gt;
&lt;li&gt;前门(The Front Gate)。遥远写字楼门口冷静的小门童。只接收投递到&amp;quot;这栋楼&amp;quot;的包裹,其他一律拒收。不会读书。&lt;/li&gt;
&lt;li&gt;内核妈妈(Mama Kernel)。办公室经理。知道每个门, 每张桌, 每位住户。她桌上有三样法宝:整栋楼的分机黄页, 一本改地址的规则书, 和一大本&amp;quot;今天收了啥我怎么处理的&amp;quot;的流水账。冷静, 稳重, 百战成精。&lt;/li&gt;
&lt;li&gt;前置文员与后置文员(Pre-Clerk &amp;amp; Post-Clerk)。成对上班的小助理。前置文员负责每个入站包裹,有时会改改包裹外面的地址;后置文员管出站的包裹——并且手抄了一份前置文员做过的所有修改,好在出门前把地址&amp;quot;改回去&amp;quot;。&lt;/li&gt;
&lt;li&gt;走廊礼宾(The Hallway Concierge)。管楼内走廊。认得每位住户的脸。他的唯一超能力:把包裹沿着走廊&amp;quot;横着&amp;quot;送到对的门口——不上不下,只走平面。&lt;/li&gt;
&lt;li&gt;前端弗里达(Frieda the Frontend)。住在走廊里,10 号。脾气好,像个前台:接到访客的包裹,看看要求,要么自己处理,要么礼貌地转交给能处理的人。&lt;/li&gt;
&lt;li&gt;后端布鲁图(Brutus the Backend)。10 号隔壁,11 号。粗声粗气的账房先生。不和外人说话。只接弗里达递过来的包裹。真正干活的——开账本, 扣库存, 记订单。&lt;/li&gt;
&lt;li&gt;包裹(The Parcels)。故事里的每条消息都是俄罗斯套娃:一封信装进一个信封,塞进一个小包裹,再塞进一个大邮袋。每一层都写给不同的人,走不同的路。我们会看它们一层层拆开, 又一层层重新包好。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;齐活儿,开戏。&lt;/p&gt;
&lt;h2 id="第一幕点击"&gt;第一幕——点击
&lt;/h2&gt;
&lt;p&gt;Jack 想要一台烤面包机。&lt;/p&gt;
&lt;p&gt;其实他已经惦记了好几周。旧的上周日伴着一缕青烟英勇就义,吓得猫当场换了个房间。他一直在拖,因为网购总感觉比它应有的&amp;quot;更郑重&amp;quot;。但今天,他下定决心。&lt;/p&gt;
&lt;p&gt;他滑啊滑。挑中一个。点下&amp;quot;购买&amp;quot;。&lt;/p&gt;
&lt;p&gt;Jack 电脑角落里,浏览器小助手噌地弹起,打着领结,手持小夹板。他写下一张短短的便条:这位顾客想买一台烤面包机。然后开始为它披挂远行。&lt;/p&gt;
&lt;p&gt;先把便条装进一个小信封,上面写好小助手一手好字的地址。再把这个信封装进一个更大的包裹,写上&amp;quot;商店&amp;quot;的远方地址。然后整个包裹再塞进一个外层邮袋,这一层写的,是门口第一位接力快递的地址。&lt;/p&gt;
&lt;p&gt;三层。三个地址。每一层负责一段路。小助手今天已经这么干了一千遍。他把邮袋递出门外。&lt;/p&gt;
&lt;h2 id="第二幕穿越信使之海"&gt;第二幕——穿越信使之海
&lt;/h2&gt;
&lt;p&gt;第一位接力员早就等着。她接过邮袋,看一眼最外层的地址,撒腿就跑。&lt;/p&gt;
&lt;p&gt;她跑到下一位,撕掉外层邮袋——这一层使命已毕——看内层的地址,再用&amp;quot;她自己&amp;quot;的新邮袋包上,写上下一位接力的地址,交棒。&lt;/p&gt;
&lt;p&gt;如此往复。&lt;/p&gt;
&lt;p&gt;每位接力员都做同样的事:撕掉只用于上一段路的外层,看看里面的地址,再为下一段路重新打包。那个内层包裹——写着商店真正地址的那个——从不被打开。它是神圣的。它是被指定要&amp;quot;端到端旅行&amp;quot;的。&lt;/p&gt;
&lt;p&gt;如果你能把时间快进,从高空俯瞰,你会看到一个光点在接力员之间跳跃,穿越半个大陆,身后落满被丢弃的邮袋。最里面的信,相对它的信封没有移动;内层包裹也没有改变。只有最外面的那层,不断地重生。&lt;/p&gt;
&lt;p&gt;最终,在人类时间里只是眨眼一瞬,包裹抵达它命定的那栋写字楼。最后一名接力把它交到前门手里,敬个礼,转身继续夜色中的奔波。&lt;/p&gt;
&lt;h2 id="第三幕剥洋葱"&gt;第三幕——剥洋葱
&lt;/h2&gt;
&lt;p&gt;前门对邮袋内容不感兴趣。它只关心最外层写的是不是&amp;quot;这栋楼的名字&amp;quot;。确认无误,收下。它的使命完成。&lt;/p&gt;
&lt;p&gt;包裹被送进后勤办公室,内核妈妈正等着。&lt;/p&gt;
&lt;p&gt;她轻轻拾起,撕下外层邮袋——那只服务于最后一段路。她把里面的包裹放在桌上。这一层的地址的确是写给这栋楼的,而且是&amp;quot;更正式&amp;quot;的写法。对我们有利。&lt;/p&gt;
&lt;p&gt;她正要再拆一层,前置文员出现在她身边。&lt;/p&gt;
&lt;p&gt;&amp;ldquo;这件是 10 号公寓的,&amp;ldquo;他说,&amp;ldquo;销售咨询。弗里达管。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;内核妈妈点点头。前置文员拿起铅笔,轻轻在包裹外面动了两笔——把&amp;quot;整栋楼&amp;quot;的收件名,改成了&amp;quot;10 号公寓&amp;quot;的具体门牌。他翻开账本认真记下:包裹 #8472,原送达大楼,重定向至 10 号。回程记得改回。记得二字他画了三道杠。他对工作极其较真。&lt;/p&gt;
&lt;p&gt;内核妈妈拿着改好抬头的包裹,翻目录。10 号——在走廊那边,礼宾的地盘。她又加了一层小小的&amp;quot;楼内快递套&amp;rdquo;,直接写明&amp;quot;收:弗里达&amp;rdquo;,从窗口递给走廊礼宾。&lt;/p&gt;
&lt;h2 id="第四幕走廊"&gt;第四幕——走廊
&lt;/h2&gt;
&lt;p&gt;礼宾早已把走廊住户的脸背得滚瓜烂熟。前端弗里达,10 号——稳。三步并作两步,唰地把包裹从她门缝塞入。&lt;/p&gt;
&lt;p&gt;弗里达心情一如既往地阳光。她拆套——楼内快递套, 楼层那层, 一路上的原始旅行包裹——最后打开小信封,读到里面的便条。&lt;/p&gt;
&lt;p&gt;&amp;ldquo;这位顾客想买一台烤面包机。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&amp;ldquo;好嘞! &amp;ldquo;弗里达自言自语。&amp;ldquo;这是布鲁图的活儿。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;她抽出一张白纸,写下&amp;quot;有顾客想买一台烤面包机——请处理&amp;rdquo;。装进她自己的小信封,抬头写&amp;quot;11 号&amp;rdquo;,再套上她自己的小快递套,从门缝推出去给礼宾。&lt;/p&gt;
&lt;p&gt;这点很关键。弗里达没有把&amp;quot;原包裹&amp;quot;转发给布鲁图;她是写了&amp;quot;一份新的&amp;quot;包裹,代表她自己向布鲁图提出同一请求。原包裹就像一张凭据,被她留在桌上。待会儿还要用。&lt;/p&gt;
&lt;p&gt;礼宾接过弗里达的新包裹——沿走廊三步——塞入布鲁图的门缝。&lt;/p&gt;
&lt;p&gt;11 号屋里,布鲁图没抬头,听见包裹落地,叹了口气。拆。读。嘟囔:&amp;ldquo;烤面包机。顾客。行吧。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;他翻开大账本。扣掉一台烤面包机库存。在 Jack 的名下记一笔。砸上一个鲜红的大章&amp;quot;CONFIRMED&amp;quot;。再写一小条回执——&amp;ldquo;已接单,将发货,ID #42&amp;rdquo;——装进写给弗里达的小信封,从门缝推回。&lt;/p&gt;
&lt;p&gt;礼宾。三步。弗里达家门缝。&lt;/p&gt;
&lt;p&gt;弗里达看完布鲁图的回信,笑了。她转回桌上那封&amp;quot;原包裹&amp;quot;,提笔写好给&amp;quot;最初发件人——Jack&amp;quot;的回信:&amp;ldquo;订单已确认,烤面包机正在路上,感谢选购。&amp;ldquo;照来时的套娃法打包:信封里信封,外套里外套。门缝,递出。&lt;/p&gt;
&lt;h2 id="第五幕回家"&gt;第五幕——回家
&lt;/h2&gt;
&lt;p&gt;回信按来时的路径&amp;quot;镜像&amp;quot;折返。礼宾到内核妈妈。内核妈妈翻目录:发件人在&amp;quot;楼外&amp;rdquo;,&amp;ldquo;得从前门出&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;但她正要为出站打包,后置文员来了,啪地翻到包裹 #8472 那页。&lt;/p&gt;
&lt;p&gt;&amp;ldquo;别忘了,&amp;ldquo;他说,&amp;ldquo;这包裹进门时,我同事把抬头从大楼改成了 10 号。现在得改回。弗里达的门牌号不能出现在外发的包裹上——对外界来说,这封回信用的是&amp;rsquo;大楼&amp;rsquo;的地址,不是任何一个具体住户。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;他用铅笔把抬头改回,合上账本。&lt;/p&gt;
&lt;p&gt;内核妈妈给改好抬头的包裹穿上全新的外邮袋,交给前门。前门转手给门口第一位接力。信使之海再次接力,邮袋一层层重生,直到最后一位快递员冲上 Jack 的小路,把包裹从他家门缝塞进来。&lt;/p&gt;
&lt;p&gt;浏览器小助手郑重其事地拆开,抚平回信,朗读。&lt;/p&gt;
&lt;p&gt;&amp;ldquo;订单已确认。你的烤面包机正在路上。感谢选购。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Jack 的浏览器里,Buy 按钮静静变绿,写成&amp;rdquo;✓ 已下单&amp;rdquo;。某处,一只猫从阳光房里抬了抬眼。Jack 笑了。&lt;/p&gt;
&lt;p&gt;他心想:也太顺了吧。&lt;/p&gt;
&lt;h2 id="解码器"&gt;解码器
&lt;/h2&gt;
&lt;p&gt;其实,一点也不顺。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.shanechang.com/p/networking-journey-buying-a-toaster/how_a_web_request_travels.png"
width="1491"
height="1055"
srcset="https://www.shanechang.com/p/networking-journey-buying-a-toaster/how_a_web_request_travels_hu_9326d6dfef30a866.png 480w, https://www.shanechang.com/p/networking-journey-buying-a-toaster/how_a_web_request_travels_hu_4caa1cee948b196e.png 1024w"
loading="lazy"
alt="从 Jack 点击到屏幕上收到响应的整段旅程:浏览器里的分层打包;每一跳路由器重写以太网帧;Linux 主机上的数据通路;让回复流量&amp;#34;反向解 NAT&amp;#34;的 conntrack 快照;在 podman0 桥上完全内部完成的前端到后端的那一次横向通信;以及对称的回程路径。"
class="gallery-image"
data-flex-grow="141"
data-flex-basis="339px"
&gt;
&lt;/p&gt;
&lt;p&gt;以下是每位角色&amp;quot;真实身份&amp;quot;的演职员表。像看谢幕后名单一样看它,然后意识到:刚刚那场戏,比你以为的精巧多了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Jack 与他的浏览器小助手:一位用户和他电脑上的浏览器。浏览器把&amp;quot;我点了购买&amp;quot;这种人类意图,翻译成服务器必须收到的那串消息。&lt;/li&gt;
&lt;li&gt;小助手写的&amp;quot;便条&amp;quot;与那一层层套娃:这才是整出戏的灵魂,得多说两句。
&lt;ul&gt;
&lt;li&gt;每条穿越互联网的消息,都是层层嵌套的套娃。最里面那张便条是实际内容——在我们这里是&amp;quot;买一台烤面包机&amp;rdquo;。它叫 HTTP 请求,是浏览器和网站说话的语言。&lt;/li&gt;
&lt;li&gt;其外是一层 TCP segment——加上可靠性功能(序列号, 重传, 确认回执),万一路上有丢件,能发现并补发。TCP 让互联网&amp;quot;像回事儿&amp;quot;;没有它,打开网页就像抛硬币。&lt;/li&gt;
&lt;li&gt;再外是一层 IP packet——写着端到端&amp;quot;谁发给谁&amp;quot;的地址。它说&amp;quot;这是发往商店公网地址的&amp;quot;。按故事设定,这一层基本不会在中途被打开或修改,它从端到端&amp;quot;穿越&amp;quot;。&lt;/li&gt;
&lt;li&gt;最外是一层 Ethernet frame——最大号的邮袋。它只认识&amp;quot;下一跳是谁&amp;quot;。每一跳上路前,这一层都会被撕掉, 重写,再交给下一位。&lt;br&gt;
这套嵌套——HTTP 信里,TCP 外套,IP 再外套,以太网最外套——正是学校里讲的&amp;quot;OSI 模型&amp;quot;在人话里的模样:一个给不同受众的&amp;quot;包里包&amp;quot;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;信使之海:互联网上的路由器。每台只知道&amp;quot;下一跳&amp;quot;,合在一起便能接力跨洲。那只&amp;quot;IP 包端到端不变,只有以太网帧每跳重写&amp;quot;的事实,才是互联网能跑起来的关键:里层能活到终点,外层随时换新。&lt;/li&gt;
&lt;li&gt;前门:面向外网的网卡(NIC)。在 Linux 主机上通常叫 eth0。职责如故事所述:收下发给我们的帧,丢掉其余,递给内核。&lt;/li&gt;
&lt;li&gt;内核妈妈:Linux 内核本尊。她拥有所有接口, 所有路由决定, 所有地址改写, 所有在飞行中的连接。她查的&amp;quot;黄页&amp;quot;是内核路由表(routing table),身边那本&amp;quot;改地址规则书&amp;quot;是 iptables/netfilter,她记的大账本是 conntrack 表。&lt;/li&gt;
&lt;li&gt;前置文员与后置文员:iptables 的 PREROUTING 与 POSTROUTING 挂钩。它们做的是 NAT(网络地址转换)。故事里的&amp;quot;进站改目的地到内部门牌&amp;quot;是 DNAT(目的地址转换)。后置文员要在出站&amp;quot;改回&amp;quot;的原因,是让外界只看见大楼的公网地址,而不是任何内部门牌。&lt;/li&gt;
&lt;li&gt;走廊礼宾:内核里的虚拟桥(virtual bridge)。在跑容器的 Linux 主机上,常叫 docker0 或 podman0。它的行为和我们在上一篇里研究的&amp;quot;交换机&amp;quot;一模一样:按名字在同一走廊里把包裹送到对应住户;至于它是软件不是铁盒子,只是实现细节。&lt;/li&gt;
&lt;li&gt;前端弗里达与后端布鲁图:两只容器(containers),各自住在隔离的&amp;quot;小公寓&amp;quot;里。弗里达可能跑着 nginx 这样的前端;布鲁图可能是数据库或订单处理 API。它们都插在同一条内部走廊(bridge)上,但彼此——以及对整栋楼以外——都有严格隔离,细节我们后面还会聊。
&lt;ul&gt;
&lt;li&gt;弗里达&amp;quot;重写一份新包裹给布鲁图&amp;quot;而不是&amp;quot;简单转发原包裹&amp;quot;的那个瞬间,正是反向代理的真实工作方式:它把一个对外会话,拆成了两个独立的会话,中间用应用层&amp;quot;粘&amp;quot;起来;不是一根管子直通。这个区别比听上去重要,我们后面会展开。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;10 号与 11 号, 走廊与大楼:这些就是你在上一篇和本文里反复看到的 IP。弗里达的门牌是 10.88.0.10,布鲁图是 10.88.0.11,走廊网段是 10.88.0.0/16,主机(内核妈妈在走廊上的座位)是 10.88.0.1。大楼的公网地址,则取决于外界怎么看到这台主机。&lt;/li&gt;
&lt;li&gt;那段&amp;quot;外界看不见&amp;quot;的弗里达与布鲁图的对话:这就是桥上的容器间通信。注意它没过 NAT,没走什么复杂路由,没碰外部接口。两间公寓,一条走廊,礼宾横向递包。便宜, 快, 对外隐形。这也是为什么 bridge 上容器互通飞快——内核几乎没离开底层。&lt;/li&gt;
&lt;li&gt;两本&amp;quot;对上暗号&amp;quot;的账本:连接跟踪(conntrack)。内核记住每条活动连接以及为它做过的改写,让回复流量能完美&amp;quot;反解&amp;quot;回去,尽管改写当初是&amp;quot;单边&amp;quot;的。没有它,地球上没有任何 NAT 能工作;有了它,现代互联网(你家路由器每天为家里每台设备干的事)就能悄无声息地运转。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="啊哈时刻"&gt;啊哈时刻
&lt;/h2&gt;
&lt;p&gt;我那位饭搭子一听&amp;quot;互联网&amp;quot;,脑海里大概飘过一根气动管道:这头塞东西,那头吐出来,中间是魔法。&lt;/p&gt;
&lt;p&gt;可中间不是魔法。中间是一串小而笨而相同的角色,每个包裹只做一件小事情,彼此并不知情,也不关心内容。所谓&amp;quot;聪明&amp;quot;,全在两端——浏览器小助手把每层地址写对,接收方把层层包裹拆开并回信。中间只是好心路人传纸条。&lt;/p&gt;
&lt;p&gt;在写字楼里,这种&amp;quot;接力&amp;quot;继续。内核妈妈比任何一个接力员都复杂——她能改地址, 能路由, 能记账——但她本质上仍是一串小机器:门口收件,撕最外层,看地址,必要时改地址,查下一跳,重新包好,从正确的内门送出去。这是条流水线,不是魔法阵。只要你别把它想象成&amp;quot;一大步&amp;quot;,就能把它整个装进脑子里。&lt;/p&gt;
&lt;p&gt;在我脑中,第一声&amp;quot;咔哒&amp;quot;是交换机那一刻——它让我看清&amp;quot;一瞬间, 一地点发生了什么&amp;quot;。第二声&amp;quot;咔哒&amp;quot;是这台烤面包机的旅程——让我看清&amp;quot;一整段路上发生了什么&amp;quot;。两者拼在一起,就顺了。&lt;/p&gt;
&lt;h2 id="我还没想明白的"&gt;我还没想明白的
&lt;/h2&gt;
&lt;p&gt;故事里有个地方我悄悄糊弄过去了。&lt;/p&gt;
&lt;p&gt;包裹到了弗里达那里时,我说&amp;quot;她的本地内核&amp;quot;剥了外衣,&amp;ldquo;她的门缝&amp;quot;收了快递,&amp;ldquo;她的桌上&amp;quot;放着原始包裹。看起来,弗里达似乎有她自己的小宇宙:自己的大门, 自己的 loopback, 自己的门牌, 自己的一切。&lt;/p&gt;
&lt;p&gt;可弗里达不是一台单独的电脑。她只是跑在和内核妈妈同一台主机上的一个进程。整栋楼只有一个内核,只有一套硬件。&lt;/p&gt;
&lt;p&gt;那弗里达的&amp;quot;公寓&amp;quot;究竟怎么&amp;quot;存在&amp;quot;的? 她如何拥有自己的内部地址, 自己的 loopback, 自己看见的走廊,却又互不踩到隔壁布鲁图的地盘? 同一个内核,怎么能并排跑出多套&amp;quot;平行网络世界&amp;rdquo;,而每一套都以为&amp;quot;世界里只有我&amp;rdquo;?&lt;/p&gt;
&lt;p&gt;答案就是我在上一篇挥手路过, 这篇终于要扣的那枚扣子:network namespace(网络命名空间)。一旦它&amp;quot;咔哒&amp;quot;落位,你就会明白为什么容器&amp;quot;像是独立的小电脑&amp;quot;。它也是 VPN, 沙箱, 很多零信任网络的地基——也是我这整个系列慢慢铺垫的那个 bug 的底层缘由。&lt;/p&gt;
&lt;p&gt;我会讲到的。我保证。&lt;/p&gt;
&lt;p&gt;下回见——看我先掉进哪只兔子洞。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;(人类撰写,必要处由 AI 协助润色)&lt;/p&gt;</description></item><item><title>交换机到底在做什么</title><link>https://www.shanechang.com/zh-cn/p/networking-journey-portainer-and-switches/</link><pubDate>Tue, 12 May 2026 00:00:00 +0000</pubDate><guid>https://www.shanechang.com/zh-cn/p/networking-journey-portainer-and-switches/</guid><description>&lt;img src="https://www.shanechang.com/p/networking-journey-portainer-and-switches/cover.webp" alt="Featured image of post 交换机到底在做什么" /&gt;&lt;p&gt;这事儿我以前干过十几次,本该手到擒来。&lt;/p&gt;
&lt;p&gt;思路很直:在笔记本上跑 Portainer(Docker 管理界面),远端服务器装 Portainer Agent,用 Cloudflare Tunnel 打通,让俩端点隔着 SSH(再套一层 Cloudflare Access)聊得不亦乐乎,外网啥都看不到。&lt;/p&gt;
&lt;p&gt;所有零件我都摸过:SSH 隧道, Docker, Portainer, Cloudflare。没有新东西。&lt;/p&gt;
&lt;p&gt;但这次,它罢工了。&lt;/p&gt;
&lt;p&gt;远端 Agent 在听;本地 UI 在跑;我在终端里手搓 curl,两个端点都能打通。可一到 Portainer 的 UI 上点 Connect,直接给了我联网界最干净, 也最无情的报错:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Get &amp;#34;https://host.containers.internal:19001/ping&amp;#34;: dial tcp 10.88.0.1:19001: connect: connection refused
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;connection refused。不是&amp;quot;打不通&amp;quot;, 不是&amp;quot;没路由&amp;quot;,而是有人在门口把门砰的一声给你摔上。&lt;/p&gt;
&lt;p&gt;我盯着这个报错沉默了挺久。链路里每个环节单测都绿了:Agent 在听, SSH 隧道也绑好了端口, 笔记本上 curl 隧道端口通, Portainer 的容器也健康。&lt;/p&gt;
&lt;p&gt;零件都没毛病。错误里倒是冒出了两个我平时从来不细想的东西:一个是我说不清来路的地址 10.88.0.1,另一个是我习惯性手就能敲出来, 但其实没想过含义的名字 host.containers.internal。&lt;/p&gt;
&lt;p&gt;就在那一刻,我意识到问题在哪了。&lt;/p&gt;
&lt;h2 id="老实交代"&gt;老实交代
&lt;/h2&gt;
&lt;p&gt;我这些年靠的是&amp;quot;背命令&amp;quot;。&lt;/p&gt;
&lt;p&gt;会敲 ssh -L,知道能转端口;会写 docker run -p 9001:9001,知道能&amp;quot;暴露&amp;quot;端口;127.0.0.1 是 localhost,这谁不知道呢。用得多了,肌肉记忆就接管了大脑。真出问题了,也常常是 Stack Overflow 换个 flag 继续莽过去,完全没把&amp;quot;为啥&amp;quot;搞明白。&lt;/p&gt;
&lt;p&gt;大学学过 OSI 模型,七层背得贼溜:物理, 数据链路, 网络, 传输, 会话, 表示, 应用。考试问我肯定能全答上来。但&amp;quot;网桥&amp;quot;和&amp;quot;路由器&amp;quot;的区别? 说实话,那会儿我真讲不明白。工作了好多年,也靠着上层抽象把活儿干了,下边几层就当不存在一样。&lt;/p&gt;
&lt;p&gt;可它们真的在那,躺着不响。公司规模一大,需求往往就顺着蛋糕的切面往下探:反向代理, 流媒体, 多地域容灾, 零信任, 还有那句灵魂拷问&amp;quot;为啥开发环境行, 预发就不行&amp;quot;。每一个都戳在我一直糊弄过去的知识空洞上。&lt;/p&gt;
&lt;p&gt;这次也是:容器里报 connection refused,目标明明是我笔记本上开的口子。错不在工具,错在我自己那点&amp;quot;差不多先生&amp;quot;式的心态。&lt;/p&gt;
&lt;p&gt;所以我决定补课。&lt;/p&gt;
&lt;p&gt;这是一篇开放式系列的第一篇。我不写教科书(世界不缺,作者也不该是我),我就盯着当前把我卡住的那一层,刨到不困惑为止,然后再往下一层挖。Portainer 这次的事故会作为主线,每篇都回到它。&lt;/p&gt;
&lt;p&gt;等这个系列写完,开头那条报错应该能像读中文一样,一眼看懂。&lt;/p&gt;
&lt;p&gt;而这篇要搞清的第一件事是:在这次问题所涉及的&amp;quot;最低那一层&amp;quot;,到底发生了什么。10.88.0.1 到底是谁? 它跟 127.0.0.1 有啥区别? 所谓&amp;quot;桥(bridge)&amp;ldquo;到底是个啥玩意儿?&lt;/p&gt;
&lt;h2 id="等等我电脑里头的网络自己是咋转的-"&gt;&amp;ldquo;等等,我电脑里头的网络,自己是咋转的? &amp;quot;
&lt;/h2&gt;
&lt;p&gt;先说把我拍醒的那一巴掌。&lt;/p&gt;
&lt;p&gt;远端 Agent 监听 19001;我把笔记本的 19001 用 SSH 隧道转到了远端的 19001;我在笔记本上 curl https://127.0.0.1:19001/ping,回得干干净净。&lt;/p&gt;
&lt;p&gt;但同一台笔记本上, 跑在容器里的 Portainer Server,去连同样的地址,却得到&amp;quot;connection refused&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;同一台机器, 同一个内核, 同一个端口号,结果居然不一样?&lt;/p&gt;
&lt;p&gt;怎么可能?&lt;/p&gt;
&lt;p&gt;我先前的直觉模型是错的:一台电脑就&amp;quot;一张网&amp;rdquo;,不是么? &amp;ldquo;我的机器&amp;quot;要么能到,要么到不了。如果我在终端 curl 成功,那同一台机器上跑的别的东西也应该能成功。&lt;/p&gt;
&lt;p&gt;这个模型从很久以前就不对了。现代 Linux 不是&amp;quot;一张网&amp;rdquo;,而是&amp;quot;网中之网&amp;quot;——在一个内核里拼出了好几张网。容器, 虚拟机, VPN, 乃至普普通通的 SSH 隧道,全靠这件事成立。只不过平时不需要想,直到有一天它以一种别扭的姿势坏给你看。&lt;/p&gt;
&lt;p&gt;要解释为啥容器看不见我终端能看到的东西,我得从最笨, 最底层的那个家伙讲起:容器和宿主之间,那台&amp;quot;虚拟交换机&amp;quot;。&lt;/p&gt;
&lt;p&gt;我用一个小剧场讲,稍微忍耐一下。演员阵容不大。&lt;/p&gt;
&lt;h2 id="小剧场会议室与递条子的前台"&gt;小剧场:会议室与递条子的前台
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Margaret:会议室中间的前台,耐心无限,手里拿个小本本。一天到晚就干一件事:给桌子边的人传纸条。&lt;/li&gt;
&lt;li&gt;Alice, Bob, Carlos:坐在桌边的三位同事。每人胸前都别着一张奇怪的名牌,比如 aa:42:81:9c:0e:33,机器印的,看着就不像给人类读的。&lt;/li&gt;
&lt;li&gt;小本本:只记录&amp;quot;谁坐在哪个座位&amp;quot;。没人教她怎么记,都是她自己观察写下的。&lt;/li&gt;
&lt;li&gt;纸条:对折的小条,外面写&amp;quot;要给谁&amp;quot;(名牌),里面写内容。Margaret 只看外面,不看里面。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;故事开始。&lt;/p&gt;
&lt;h3 id="会议室的一天"&gt;会议室的一天
&lt;/h3&gt;
&lt;p&gt;Alice 第一天来上班,挑了个空位——3 号,坐下。&lt;/p&gt;
&lt;p&gt;Margaret 并不知道 Alice 的存在,小本本里也没 Alice 的记录。&lt;/p&gt;
&lt;p&gt;过会儿,Alice 写了张&amp;quot;早上好&amp;quot;要给 Carlos,递给 Margaret。Margaret 看外面写的收件人是 Carlos,心里想&amp;quot;Carlos? 他在 7 号位&amp;quot;,然后把纸条递到了 7 号。&lt;/p&gt;
&lt;p&gt;走之前,Margaret 顺手扫了眼纸条外面的&amp;quot;发件人&amp;quot;——Alice 的名牌,又看了眼她刚拿纸条的座位,刷刷写进小本本:
Alice(aa:42:81:9c:0e:33)— 3 号位。&lt;/p&gt;
&lt;p&gt;十分钟后,Bob(5 号位)要给 Alice 写条子。Margaret 翻开本子,查到 Alice 在 3 号,稳准快送达。&lt;/p&gt;
&lt;p&gt;这就是 Margaret 的理想工作流:她认识的人,翻一页就送到。&lt;/p&gt;
&lt;p&gt;可如果在她&amp;quot;还不认识 Alice&amp;quot;的那五分钟里,Bob 突然要给 Alice 送条呢? 这会儿 Alice 还没发过任何纸条,Margaret 根本就没法在本子里查到她。&lt;/p&gt;
&lt;p&gt;Margaret 会摊手, 然后干一件粗暴而有效的事:把这条纸条复印一堆,除了 Bob 的座位,其他每个人都发一份。谁是 Alice 谁就回,其他人看一眼不是自己的名牌,就丢纸篓里。&lt;/p&gt;
&lt;p&gt;这就是 Margaret 的&amp;quot;全活&amp;quot;。两个动作:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;查得到就直达(forwarding);&lt;/li&gt;
&lt;li&gt;查不到就全发(flooding)。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而且每一条她经手的纸条——不管是直达的还是要全发的——她都会顺便学习:这条从 3 号位来的, 发件人名牌 aa:42:81:9c:0e:33——记上。新同事只要发过一条,Margaret 就知道他在哪了,而且不会记错——因为她只记录亲眼所见。&lt;/p&gt;
&lt;h3 id="把戏拆穿她在计算机里是谁"&gt;把戏拆穿:她在计算机里是谁
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Margaret 就是一台交换机(switch)。在软件里也叫桥(bridge),算法一模一样。机房里那种金属盒子是硬件交换机;Linux 内核里的数据结构是软件网桥。行为一致。&lt;/li&gt;
&lt;li&gt;&amp;ldquo;座位&amp;quot;是交换机的端口(port)——插网线的那个口。注意这可不是 TCP 端口,撞名了而已。&lt;/li&gt;
&lt;li&gt;名牌是 MAC 地址。网卡出厂就刻着,长得就像 aa:42:81:9c:0e:33。&lt;/li&gt;
&lt;li&gt;小本本是 MAC 地址表(MAC address table)。&lt;/li&gt;
&lt;li&gt;查得到就送叫转发(forwarding)。&lt;/li&gt;
&lt;li&gt;查不到就全发叫泛洪(flooding)。&lt;/li&gt;
&lt;li&gt;她靠&amp;quot;看见谁从哪个口发出了帧&amp;quot;来自学习(MAC learning)。不配 DHCP, 不配配置文件,插上线发一帧,交换机就知道你在哪。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;重点是:她从不看&amp;quot;纸条里写了啥&amp;rdquo;。不管上面跑 ARP, IP, TCP, HTTP,跟她都没关系。她只认&amp;quot;外面写给谁&amp;quot;,不是就全发,是就直达。这也是为啥硬件交换机能用专用芯片一秒钟转发上百万帧:逻辑简单到不能再简单。&lt;/p&gt;
&lt;h3 id="当-bob-想找一个他不认识的人"&gt;当 Bob 想找一个&amp;quot;他不认识的人&amp;quot;
&lt;/h3&gt;
&lt;p&gt;问题来了:Bob 一开始连 Alice 的名牌都不知道,他怎么写外面的&amp;quot;收件人&amp;quot;?&lt;/p&gt;
&lt;p&gt;回到剧场。&lt;/p&gt;
&lt;p&gt;今天 Bob 收到个任务:&amp;ldquo;给管烤面包机订单的人递个条&amp;rdquo;。他不知道是谁,不知道名牌,不知道座位。&lt;/p&gt;
&lt;p&gt;Margaret 帮不上忙。她的小本本只记&amp;quot;名牌—座位&amp;quot;的映射,不知道&amp;quot;谁管什么业务&amp;quot;。&lt;/p&gt;
&lt;p&gt;但 Bob 有个招:他在纸条里面写&amp;quot;你好我是 Bob,名牌 bb:11:22:33:44:55,坐 5 号。谁管烤面包机请回信告诉我你的名牌&amp;quot;。然后,重点来了,他在外面的&amp;quot;收件人&amp;quot;一栏,不写具体的名牌,而是写:&lt;/p&gt;
&lt;p&gt;FF:FF:FF:FF:FF:FF&lt;/p&gt;
&lt;p&gt;这是一个保留的&amp;quot;特殊名牌&amp;quot;。没人真的佩戴它。它的意思是:大家都听着(broadcast)。&lt;/p&gt;
&lt;p&gt;他把纸条递给 Margaret。Margaret 翻本子当然翻不到这个&amp;quot;名牌&amp;quot;,于是走她&amp;quot;查不到就全发&amp;quot;的流程:除了 Bob 的座位,其他所有座位都发一份。&lt;/p&gt;
&lt;p&gt;注意,这不是 Margaret 的&amp;quot;特判&amp;quot;,而是 Bob 主动写了一个所有人都认得的&amp;quot;大家一起上&amp;quot;的目的名牌,逼着交换机走泛洪。交换机自己分不清这是不是 ARP,更不懂&amp;quot;烤面包机&amp;quot;是何物,她只是按规矩干活。&lt;/p&gt;
&lt;p&gt;大家都收到复印件了,绝大多数人一看跟自己无关,扔了。只有 Alice——原来她就管烤面包机——认真看完回了一条,这次她把外面的收件人写成了 Bob 的真名牌,里面写:&amp;ldquo;你好,我是 Alice,我的名牌是 aa:42:81:9c:0e:33&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;Margaret 在把回条送回 5 号的同时,也顺手把 Alice 记进了本子。自此 Bob 知道了 Alice 的名牌,Margaret 也知道了 Alice 的座位,天下太平。&lt;/p&gt;
&lt;p&gt;翻译回计算机:这套来回就是 ARP(Address Resolution Protocol)。那个 FF:FF:FF:FF:FF:FF 是广播 MAC 地址。协议的精髓就是:先用广播问&amp;quot;谁是 X 的 IP 拥有者&amp;quot;,对方用自己的真 MAC 回;你记住它的 MAC,以后就可以直连。&lt;/p&gt;
&lt;p&gt;两个常见&amp;quot;为什么会泛洪&amp;quot;的触发点,其实分别是:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;交换机真不认识(MAC 表里没有),只好泛洪;&lt;/li&gt;
&lt;li&gt;发送方故意把目的 MAC 写成广播地址,让交换机去泛洪。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(小彩蛋:FF:FF:FF:FF:FF:FF 全是 1 不是随便拍脑袋定的。MAC 地址第一个字节的最低位就是&amp;quot;组播/广播&amp;quot;标志,硬件只用一个按位判断就能快速认出&amp;quot;这玩意儿要大家一起看&amp;quot;。从设计之初就给硬件友好了。)&lt;/p&gt;
&lt;h2 id="会议室变成虚拟的了"&gt;会议室变成&amp;quot;虚拟&amp;quot;的了
&lt;/h2&gt;
&lt;p&gt;刚才说的是物理交换机的世界:铁盒子, 网线, 端口。&lt;/p&gt;
&lt;p&gt;我笔记本上的那台交换机是&amp;quot;虚拟&amp;quot;的,跑在 Linux 内核里,叫 bridge。Docker 默认叫 docker0,Podman 默认叫 podman0。行为跟物理交换机一模一样:一本 MAC 表,两个动作,广播照做,其他一概不懂。区别只是:Margaret 入驻了内核,这间房间是内存里的数据结构,不是铜线和晶体管。&lt;/p&gt;
&lt;p&gt;容器启动时,内核会造一根&amp;quot;虚拟网线&amp;quot;(veth pair),就像一根两头的线:一头塞进容器里,变成容器看到的 eth0;另一头插在 Margaret 的会议室里某个座位上。内核保证&amp;quot;一端进,另一端出&amp;quot;,就是这么朴素。&lt;/p&gt;
&lt;p&gt;关键点:宿主机自己也坐在 Margaret 的房间里。房间一搭好,内核就让宿主也占个座,配个名牌,再配个 IP。Margaret 不在乎谁是宿主, 谁是容器,反正都是戴着名牌的&amp;quot;人&amp;quot;,她只按规矩转纸条。&lt;/p&gt;
&lt;p&gt;在这一层,Docker/Podman 干的其实是三件无聊但重要的小事:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;让内核建房(bridge);&lt;/li&gt;
&lt;li&gt;容器启停时,用 veth 把它们插上/拔下;&lt;/li&gt;
&lt;li&gt;确保宿主机也在房里有自己的座位。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;至于&amp;quot;怎么转发&amp;quot;,全是内核在干,容器运行时只是搭台。&lt;/p&gt;
&lt;p&gt;这下我的报错顺了:10.88.0.1 是 Podman 这间房(podman0)里,宿主机那个座位的 IP。站在容器的视角,它就是&amp;quot;房里那个坐着宿主的口子&amp;quot;。host.containers.internal 不过是它的一个顺口的 DNS 别名(Docker 一样,只是常见的是 172.17.0.1,对应 docker0 里的宿主座位)。&lt;/p&gt;
&lt;h2 id="但整栋楼不止这一个房间"&gt;但整栋楼不止这一个房间
&lt;/h2&gt;
&lt;p&gt;既然宿主在 podman0 这间房里是 10.88.0.1,那 127.0.0.1 呢? 那个&amp;quot;本机地址&amp;quot;是啥?&lt;/p&gt;
&lt;p&gt;127.0.0.1 是另一间房。&lt;/p&gt;
&lt;p&gt;想象公司走廊的另一头,还有个超小的私人房间,只有一个座位——你的。房里也有个前台,叫 Lorraine。她的工作更简单:你给她纸条,她走两步又把纸条递回你手上。房里没人,纸条永远不会离开这个小房间。&lt;/p&gt;
&lt;p&gt;Lorraine 是回环接口(loopback,lo,对应 127.0.0.1)。所有 Linux 主机都有这么一间&amp;quot;自言自语室&amp;quot;。&lt;/p&gt;
&lt;p&gt;重点来了:宿主机同时坐在两间房里。它在 Margaret 的房里有个座(10.88.0.1),也在 Lorraine 的房里有个座(127.0.0.1)。不同房,不同前台,不同地址。&lt;/p&gt;
&lt;p&gt;而当一个程序想&amp;quot;监听&amp;quot;某个端口时,它其实是在决定:把&amp;quot;门卫&amp;quot;安排在哪间房门口。监听 127.0.0.1,门卫就站在 Lorraine 的房里;监听 10.88.0.1,门卫就站在 Margaret 的房里;监听 0.0.0.0,那就每间房门口都站一个(只要宿主在那间房里有座)。&lt;/p&gt;
&lt;p&gt;我的 bug 就卡在这一步。&lt;/p&gt;
&lt;p&gt;我的 SSH 隧道在本地&amp;quot;开监听&amp;quot;(把 19001 口子开起来,进来的连接全转发到远端)时,默认把门卫安排在了 127.0.0.1。也就是说,门卫一直蹲在 Lorraine 的小黑屋里。&lt;/p&gt;
&lt;p&gt;我在宿主上跑 curl https://127.0.0.1:19001/ping,那当然通——我是在 Lorraine 的房里敲门,门卫就在眼前。&lt;/p&gt;
&lt;p&gt;可容器在 Margaret 那间大房里,它去找的是宿主在这间房的门——10.88.0.1:19001。容器的请求到了 Margaret 的房门口,敲了半天,门卫不在这屋啊! 这屋没人听,宿主在这间房的这个口子上没有监听,回答自然就是:connection refused。&lt;/p&gt;
&lt;p&gt;解决方案一旦看清楚,简单得有点丢人:把 SSH 隧道的监听绑定到 10.88.0.1,或者干脆 0.0.0.0。反正让门卫出现在容器真正会来敲门的那间房就行。&lt;/p&gt;
&lt;p&gt;但要走到&amp;quot;简单得丢人&amp;quot;的这一步,我得先知道&amp;quot;原来有好几间房&amp;quot;。要知道有房,得懂&amp;quot;bridge&amp;quot;是啥;要懂 bridge,得知道 Margaret 只干两件事。这就是为啥这篇要从这里开刀。&lt;/p&gt;
&lt;h2 id="讲明白了吗"&gt;讲明白了吗?
&lt;/h2&gt;
&lt;p&gt;比之前强多了,但还没圆满。&lt;/p&gt;
&lt;p&gt;我现在知道了 10.88.0.1 为啥重要, 它跟 127.0.0.1 有啥本质区别。我能在脑子里看见 Margaret 的会议室:容器占一个座, 宿主占一个座,前台按&amp;quot;名牌—座位&amp;quot;把纸条转来转去,不懂上层协议。也知道为啥&amp;quot;只在某个接口上监听&amp;quot;的服务,会对来自另一间房的敲门视而不见。ARP 也不再神秘了:只是 Bob 用&amp;quot;大家一起看&amp;quot;的目的 MAC 问了一嗓子,交换机忠实地泛洪,因为它只会干这件事。&lt;/p&gt;
&lt;p&gt;但一个更大的问号冒出来了:上面的故事默认&amp;quot;容器有自己的网络栈,可以插到 Margaret 的房里&amp;quot;。可容器归根结底只是跑在同一个内核里的进程,它怎么会&amp;quot;有自己的一块网卡, 一个 IP, 甚至有自己的一间 Lorraine 小黑屋的 127.0.0.1&amp;quot;,而且跟宿主的 127.0.0.1 互不干扰?&lt;/p&gt;
&lt;p&gt;再想想——我总说&amp;quot;容器是隔离的&amp;quot;。到底隔离的是什么? 用的是什么机制? 内核里哪一层在实施这个隔离?&lt;/p&gt;
&lt;p&gt;一个坑刚填平,下面就是个更大的坑。&lt;/p&gt;
&lt;p&gt;答案是 Network Namespace。它让一台 Linux 机器在内核里&amp;quot;分身多用&amp;quot;,同时跑出很多套&amp;quot;自以为是全世界的网络栈&amp;quot;,每一套都有自己的 127.0.0.1。容器, VPN, 很多现代基础设施的魔法,都栖身于此。一旦这个概念卡进脑子,前面提到的 veth 从比喻,变成了看得见摸得着的&amp;quot;管子&amp;quot;。&lt;/p&gt;
&lt;p&gt;下篇见,我们从这里开始挖。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;(人类写作,必要处参考了 AI 的点子与润色。)&lt;/p&gt;</description></item></channel></rss>