🌐 第三章 网络间的通用语言TCP/IP
📄 一句话概括

你在浏览器里敲一个域名,IP 就"自动"来了——这个"自动"背后是两件东西在干活:你电脑里那个叫 DNS 解析模块的软件部件(负责组装查询包、决定问谁、超时重试),和网络上一台本地 DNS 服务器(负责替你一层层问到底)。而它俩之间那次"帮我查出来就行"的委托,就叫递归查询;服务器给你的每一条答案,都是一条格式固定的资源记录。

📝 本节和 3.21 的分工(别混)

3.21 讲的是电话簿的全局结构:域名怎么读、DNS 为什么分三层、一次查询大概走几趟。 本节把镜头推到执行机构上——三件当时只露了个面的东西: 1. 资源记录:3.21 列了一张类型表,本节讲一条记录内部有几栏、每栏什么意思 2. DNS 解析模块:3.21 压根没提,但它才是你每次上网真正在用的那个部件 3. 递归查询:3.21 只跟迭代做了个对比,本节讲递归的边界划在哪、谁来扛代价

📝 本节在第三章里的位置

3.21 打开了应用层的大门("应用程序自己定义的规则"),本节讲这套规则的执行细节——一个应用层协议怎么被本机调用、怎么被组织成一次次的远程问答。

一、先分清两种"自动获取地址"

标题里的"自动获取"这四个字,前面已经出现过一次——3.12 的 DHCP。两个都是"自动",方向却正好相反,先把这个岔路口标清楚:

DHCP(3.12) DNS(本节)
自动获取的是 自己的地址 对方的地址
大小 一套四件套(IP/掩码/网关/DNS) 一个(或一组)IP
谁给的 网络里的 DHCP 服务器 网络里的 DNS 服务器
什么时候要 接入网络时,一次 每次要用域名时,反复
不工作会怎样 掉进 169.254.x.x 自保 报「找不到主机」

一句话总结这个岔路口:

❗ 一句话立论

DHCP 管"我是谁",DNS 管"别人在哪"。

前者让你接入这个网络,后者让你使用这个网络。

先 DHCP 拿到自己的四件套  ──►  才有资格去问 DNS  ──►  才访问得了别人
(3.12)                            (3.21 / 本节)

这也顺手解释了 3.12 为什么把 DNS 服务器地址放进四件套里一起发——它是"能不能上网"的前置条件,不是可选项。少了它,网络是通的,但你一个网站都打不开(因为不知道该往哪送)。

⚠️ 别把两个"DNS 服务器"搞成一个

这个词在本节出现两次,指的不是同一个东西:

说法 在哪 是什么
DNS 解析模块 你的电脑里 一个软件部件(一段程序),负责"办事"
本地 DNS 服务器 网络上(路由器或运营商) 一台真正的服务器,负责"回答"

一个是办事员,一个是档案馆。本节就是要把这两个角色彻底分开。

二、资源记录:电话簿里的"一行"到底有几栏

3.21 说 DNS 存的是资源记录(Resource Record,RR),还列了 A / AAAA / CNAME / MX / NS / PTR 那张类型表。本节把它放大——任何一条记录,不管什么类型,都由固定的五段组成。

字段 名字 含义 实例
Name 名称 查的是谁 www.baidu.com.
Type 类型 要哪一类答案 A
Class 类 记录属于哪个"协议族" IN(Internet,几乎总是它)
TTL 生存时间 这条答案允许被缓存多少秒 300
RDATA 数据 答案本体,内容随类型而变 110.242.68.66

前两段决定"这是什么",后三段决定"能活多久、指向谁"。换类型,其实只换最后一段的内容:

类型 RDATA 里放什么 举例
A 一个 IPv4 地址 110.242.68.66
AAAA 一个 IPv6 地址 240e:83:201:xx::1
CNAME 另一个域名(别名指向) baidu.com.
MX 邮件服务器的域名 + 优先级 10 mx.baidu.com.
NS 管这个域的服务器域名 ns1.baidu.com.
PTR 一个域名(反向用) www.baidu.com.
TXT 一段任意文字 v=spf1 include:...
SOA 这个区域的管理信息 见下

一条记录用文本写出来长什么样

DNS 服务器的配置(区域文件 zone file)就是一行一条记录,格式正是上面那五段:

www.baidu.com.    300   IN   A       110.242.68.66
www.baidu.com.    300   IN   CNAME   baidu.com.
baidu.com.        300   IN   NS      ns1.baidu.com.
baidu.com.        300   IN   MX  10  mx.baidu.com.

几个必须注意的书写习惯:

❗ TTL 是"记录自己身上的字段"

3.21 讲了"缓存要等 TTL 过期才更新",本节补上它的出处:

TTL 不是缓存定的,是记录自带的。 每次你拿到一条记录,就等于拿到了它的"保质期"。你的电脑缓存 300 秒、本地 DNS 也缓存 300 秒——同一条记录,各级缓存各算各的倒计时。

所以 3.21 那个经典困惑("我明明改了解析,为什么还是访问到旧服务器")在配置侧的解法很具体:先把 TTL 改小(比如 60 秒),等各级缓存过期后再改 IP,这样切换窗口只有一分钟。

两个值得一提的补充类型

SOA(Start of Authority)——一个区域的"户口本第一页"

每个域(区域)都有一条 SOA,它不回答"某台机器的 IP",而是记录这个区域本身的管理信息:

baidu.com.  3600  IN  SOA  ns1.baidu.com. admin.baidu.com. (
                        2026092001  ; 序列号:改动一次 +1
                        7200        ; 从服务器多久来问一次
                        3600        ; 问不到时的重试间隔
                        1209600     ; 多久没联系上就算失效
                        300 )       ; 没有 TTL 时的默认值

其中 序列号是多台 DNS 服务器之间同步的依据——从服务器发现序列号变大了,才拉新数据。这也是"改了 DNS 但没生效"的另一个可能原因(序列号忘了加)。

通配符记录——*.example.com 一条记录管住所有没单独定义的主机名。省事,但也容易把"本该查不到的名字"变成一个奇怪的地址。

📝 查询报文和响应报文里装的也是它

3.21 讲"解析模块组装查询包"时没展开,这里补一句:DNS 报文的"问题"部分放的是 Name + Type + Class 三段,响应部分的"答案"部分放的是五段齐全的记录。

换句话说:你问的时候给三个字段,它答的时候还你五个字段——多出来的 TTL 和 RDATA 就是"答案"和"保质期"。

三、DNS 解析模块:装在你电脑里的"办事员"

现在进入本节最有价值的一段。

3.21 讲"你只问一次,剩下的本地 DNS 替你跑腿",可是——那个"问"的动作,是谁做的?

不是浏览器,也不是你。是你操作系统里的一个部件:DNS 解析模块(正式叫法 stub resolver,"存根解析器")。

❗ 它不是一个服务器,是一段程序

解析模块住在你的电脑里(Windows 里由一个叫 DNS Client(服务名 Dnscache) 的系统服务负责),它自己不存任何域名的答案,只干三件事:

  1. 组装查询包 —— 把你给的域名填进 Name 段,把"要 A 记录"填进 Type 段
  2. 决定问谁、按什么顺序问 —— 先查本机缓存、再查 hosts、最后才去问 DNS 服务器
  3. 管超时和重试 —— 第一台服务器没响应就换下一台,等到期还不行就告诉程序"查不到"

(第一张图左边那半就是它。)

为什么要专门有这么一层? 因为每个想上网的程序都不该重复造这套轮子。浏览器、ping、Java 的 InetAddress、系统的自动更新——它们统统是把这个域名丢给解析模块,然后等结果。

💡 收 Java 13.1 的账(这次是完整版)

13.1 里这行代码:

InetAddress baidu = InetAddress.getByName("www.baidu.com");

getByName() 表面上是 Java 的一个静态方法,实际上它只是把域名递给了操作系统的解析模块,然后一直等。整套"查缓存 → 读 hosts → 发 DNS 查询 → 超时重试"一条龙,全是解析模块在跑。

这也解释了 UnknownHostException 为什么叫"Unknown Host"——它是解析模块明确告诉你"这个名字我查不到",而不是"网络断了"。收到它时该去查 DNS 配置和 hosts,不是去查网线(收 3.21 那个误区)。

解析模块的问询顺序

它出门之前,会先在本地翻两遍:

① 本机 DNS 缓存      ← 最近查过的,最快
② hosts 文件          ← 手写的小抄(3.21 讲过,优先级最高)
③ 按配置依次问 DNS 服务器   ← 这才是"出网"

第 ③ 步的"配置"在哪?就是 3.12 四件套里的第四件,用 ipconfig /all 能看到:

   DNS 服务器 . . . . . . . . . . . : 192.168.1.1
                                      223.5.5.5

可以列好几个。 解析模块的规矩是:先问第一个,超时了才问第二个。所以第一个填错了(比如填了个不存在的地址),你的网页会先卡几秒才出去——"上网慢"有时候慢在这里。

📝 你家里的 DNS 链条:路由器是个二传手

家里的情况通常是这样的:

你的电脑  ──问──►  路由器(192.168.1.1)  ──转发──►  运营商 DNS

路由器通过 DHCP 把自己的地址(192.168.1.1)当 DNS 发给你(收 3.12),你所有查询都先到它手里,它再转发上游。

这就解释了 nslookup 输出里那行"服务器"为什么常常显示 192.168.1.1——你问的是路由器,不是运营商(路由器的管理页里能看到它上游配的是谁)。

四、递归查询:这条委托的边界划在哪

(第一张图右边那半。)3.21 给过递归/迭代的对比表,本节把它落到边界上——这是最容易含糊的一处。

递归查询 迭代查询
分界线的哪一侧 左侧:你的电脑 ↔ 本地 DNS 右侧:本地 DNS ↔ 根/顶级域/权威
请求里怎么表示 RD = 1(Recursion Desired:期望递归) RD = 0
对方要做什么 必须给出最终答案(或明确报错) 只回答线索,或"我不知道"
谁在承担后续工作 被问的那台机器 问的人自己
❗ 关键一句:递归的边界,正好是"你自己"和"外面"的分界线

你的电脑只发递归查询,本地 DNS 只发迭代查询——这两句话合起来,就把整件事说完了。

3.21 那张图上的"同一个框向右发三支箭",之所以能画成一支箭发三次,就是因为那三趟全是迭代:每一趟都是本地 DNS 自己接着跑,你的电脑一概不知。

为什么是"你"能发递归,根服务器却不能

这两个问题的答案是同一个:代价由谁承担。

这个分工正是 3.21 那句"中间层越无知,可维护性越高"的另一面:越靠近顶层的服务器,做的活越少、处理的数量越大。

📝 RD 和 RA:一对标志位

DNS 报文头里有两个专门的比特:

  • RD(Recursion Desired) —— 请求里由你填:1 = "帮我查到底"
  • RA(Recursion Available) —— 响应里由服务器填:1 = "我支持递归"

所以你问根服务器时,就算填了 RD=1,它回的 RA 也常常是 0——等于礼貌地告诉你"这事我不管"。这个细节在抓包里一眼就能看见。

递归的另一重代价:缓存就是它的命

本地 DNS 为什么能把"三趟"跑得很快?因为它记得住。

情况 耗时量级 发生什么
缓存命中 亚毫秒级 直接回你,一步不出门
缓存未命中(冷查询) 几百毫秒 真的从根开始问三趟

这就是"首次访问某网站慢、之后再打开就快"的底层原因(3.21 提过,本节给数字)。

反过来说:如果一个域名从没被任何人查过,本地 DNS 也没缓存,那它就得从根一路问下来——这段时间你是干等的,且解析模块还设了超时,超了它可能就换下一台服务器重来。

💡 顺手收 3.20 的账(口径更精确了)

3.20 说"DNS 是 UDP 最典型的应用",现在能说得更准:

每一次"单趟问答"都是一个独立的 UDP 数据报。 一次完整的冷查询在网络上跑了 4 趟(你→本地,本地→根→顶级域→权威),但在本地 DNS 那侧是 3 个独立的 UDP 查询,各走各的,谁也不依赖谁——这正是 UDP 数据报"保留边界"的用法:一问一答,干干净净。

五、把"自动获取"这条路串起来

把本节和 3.21 的内容拼成一条完整的流水线:

步 谁在做 做什么
1 你 敲下 www.baidu.com,回车
2 应用程序(浏览器) 把域名交给解析模块(自己不管解析的事)
3 DNS 解析模块 查本机缓存 → 查 hosts,都没命中
4 DNS 解析模块 组装一个 RD=1 的查询包,发给配置里的第一台 DNS 服务器
5 本地 DNS 服务器 自己也查缓存,没命中 → 开始迭代问根 → 顶级域 → 权威
6 权威服务器 回一条五段齐全的 A 记录(含 TTL)
7 本地 DNS 服务器 把答案回给你的解析模块,自己缓存一份(按 TTL)
8 解析模块 把 IP 交给应用程序,自己也缓存一份
9 应用程序 拿到 IP,开始跟服务器建连接(收 3.5 的三次握手)

第 4 步的 RD=1,和第 5 步的"迭代",就是本节的全部重点。 一个包里写着"帮我查到底",另一个方向上跑着三趟"你去找他"。

六、动手 Demo36:看解析模块和资源记录

  1. 看清解析模块手里的配置(本节第一步) ipconfig /all 找「DNS 服务器」那几行——这就是解析模块的"问询名单",顺序即优先级。家里一般写着路由器的地址(192.168.1.1)。

  2. 看它缓存了些什么(资源记录的实物) ipconfig /displaydns 3.21 看过一遍,这次换个读法:每一段的 A (主机) 记录 下面都有一行 TTL——那就是本节讲的 TTL 字段,正在倒计时。往下翻还能看到 CNAME 记录——五段式的实物就在眼前。

  3. 单条查询看全五段(本节最直接的一步) nslookup -type=a www.baidu.com nslookup -type=ns baidu.com nslookup -type=mx baidu.com 三条命令问同一台服务器,要的只是不同的 Type——回来的答案 RDATA 里装的东西完全不同。这就是"五段式里只有最后一段在变"的实物证据。

  4. 换个角度理解"问谁"(顺带证明解析模块的存在) nslookup www.baidu.com nslookup www.baidu.com 8.8.8.8 第一条问你配置的那台,第二条强行问 Google 的公共 DNS。注意:nslookup 是自己实现了一套查询逻辑的,它绕过了系统的解析模块——这也是为什么它看不到 hosts(收 3.21 那个实验)。

  5. 看"根不做递归"长什么样(本节最有意思的一步) ``` nslookup

    server 198.41.0.4 www.baidu.com ``198.41.0.4` 是根域名服务器(a.root-servers.net)的地址之一。向它发一个普通的查询(RD=1),它的反应通常是下面三种之一:

  6. 回 REFUSED(拒绝服务)
  7. 回一个空的应答
  8. 只给你 .com 的 NS 记录(线索)

三种结果都指向同一件事:根服务器不做递归。 它只给你线索,剩下的路得自己走。 (看完记得 exit 退出交互模式,并把 server 改回默认。)

  1. 30 秒实验:一冷一热,感受缓存的差距 nslookup www.baidu.com ← 记下耗时感受(快) 再找一个从没访问过的域名: nslookup www.wikipedia.org ← 冷查询,可能明显慢一拍 冷热差别就是"缓存命中 vs 从根一路问下去"的直观体感。家里宽带几百毫秒不明显,企业网络或跨境域名上会非常明显。
⚠️ 第 5 步别乱试太久

向根服务器发查询属于借用公共资源,偶尔看一眼原理没问题,千万别写成脚本循环发——那属于滥用,会被根服务器侧的防护拦掉,也可能被运营商注意到。看明白原理就收手。

七、常见误区

  1. ❌ "DNS 解析模块就是本地 DNS 服务器" → 一个在你电脑里(软件部件)、一个在网络上(服务器);前者是办事员,后者是档案馆
  2. ❌ "浏览器自己会查域名" → 浏览器只是调用解析模块,自己不实现那套逻辑(少数浏览器内置 DoH 是例外)
  3. ❌ "nslookup 的结果和浏览器完全一样" → nslookup 绕过了系统解析模块,所以它不看 hosts、也不只用系统配置的那台服务器(3.21 那个 hosts 实验就是靠这一点成立的)
  4. ❌ "一条 DNS 记录就是'域名 → IP'" → 那是 A 记录的样子;五段式(Name/Type/Class/TTL/RDATA) 才是通用格式,RDATA 里可以放域名、文字、甚至优先级数字
  5. ❌ "TTL 是缓存服务器的设置" → TTL 是记录自带的字段;各级缓存拿到后各自倒计时
  6. ❌ "递归查询是全流程都叫递归" → 递归只到本地 DNS 为止。本地 DNS 问根、问顶级域、问权威,那三段全是迭代
  7. ❌ "根服务器会帮你查出 IP" → 根只给线索(.com 归谁管),且拒绝递归;答案只有权威服务器才有
  8. ❌ "解析慢就是网络慢" → 也可能是解析模块配的第一台 DNS 服务器超时了,正在等它超时后换第二台
  9. ❌ "改了解析立刻生效" → 收 3.21:各级缓存按 TTL 过期;正确做法是先把 TTL 改小再动 IP
  10. ❌ "DNS 只存在于网络上" → 你电脑里就有一整套:解析模块 + 缓存 + hosts 文件

八、动手自测

❓ 自测一下
  1. DHCP 和 DNS 都在"自动获取地址",区别在哪?
  2. "DNS 解析模块"和"本地 DNS 服务器"分别住在哪、各干什么?
  3. 解析模块出门问 DNS 之前,会先在本地查哪两样东西?
  4. 一条资源记录有哪五段?哪一段的内容会随类型改变?
  5. TTL 是谁定的?改 IP 之前为什么要先动它?
  6. 递归查询和迭代查询,分界线划在网络的哪个位置?
  7. 为什么根服务器不做递归?
  8. nslookup 为什么看不到 hosts 文件里的内容?
  9. ipconfig /all 里列了两台 DNS 服务器,它们是怎么用的?

答案: ① DHCP 自动获取自己的地址(四件套,一次),DNS 自动获取对方的地址(每次要用域名时)。DHCP 让你接入网络,DNS 让你使用网络——DNS 服务器地址本身还是 DHCP 发的。 ② 解析模块住在你自己的电脑里(Windows 里是 Dnscache 服务),是段程序,负责组装查询包、决定问谁、管超时重试;本地 DNS 服务器在网络上(路由器或运营商),是台真服务器,负责替你一层层问到底。 ③ 本机 DNS 缓存和 hosts 文件。都没命中才出门去问 DNS 服务器。 ④ Name(名称)、Type(类型)、Class(类)、TTL、RDATA(数据)。前三段(实际是前两段)决定"这是什么",只有 RDATA 随类型改变——A 放 IPv4、CNAME 放另一个域名、MX 放邮件服务器加优先级。 ⑤ TTL 是记录自带的字段,不是缓存设置的。改 IP 前先把 TTL 改小(如 60 秒),是为了让各级缓存尽快过期,缩短"新旧地址并存"的窗口——否则得等原来的 TTL 走完才生效。 ⑥ 划在你的电脑和本地 DNS 之间。左侧是递归(RD=1,必须给最终答案),从本地 DNS 往右全是迭代(RD=0,只回线索)。 ⑦ 因为它扛不住。全世界所有解析器都来问,它只做最省力的活——告诉你往哪找。越靠顶层,干的活越少、处理的数量越大。 ⑧ 因为 nslookup 自己实现了一套 DNS 查询逻辑,直接向服务器发查询,不经过系统的解析模块;而 hosts 是解析模块在"本机阶段"才查的东西。这正好证明两者的来源和路径是分开的。 ⑨ 依次用:先问第一台,超时才换第二台。所以第一台填错(或响应很慢)时,表现为"上网前几秒卡住"——不是网速问题,是在等超时。

九、下一步学什么

相关笔记