你在浏览器里敲一个域名,IP 就"自动"来了——这个"自动"背后是两件东西在干活:你电脑里那个叫 DNS 解析模块的软件部件(负责组装查询包、决定问谁、超时重试),和网络上一台本地 DNS 服务器(负责替你一层层问到底)。而它俩之间那次"帮我查出来就行"的委托,就叫递归查询;服务器给你的每一条答案,都是一条格式固定的资源记录。
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 服务器 | 网络上(路由器或运营商) | 一台真正的服务器,负责"回答" |
一个是办事员,一个是档案馆。本节就是要把这两个角色彻底分开。
二、资源记录:电话簿里的"一行"到底有几栏
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.
几个必须注意的书写习惯:
- 名称末尾那个点不能省(
www.baidu.com.)——那是 3.21 讲的根域。省了点,DNS 服务器会自动给你补上当前区域的后缀,意思就变了。这是配置 DNS 时最容易出错的一处。 - TTL 可以省略,省略时用区域文件顶部的默认值。
- 类
IN家常便饭,写配置文件时经常被省掉。
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) 的系统服务负责),它自己不存任何域名的答案,只干三件事:
- 组装查询包 —— 把你给的域名填进 Name 段,把"要 A 记录"填进 Type 段
- 决定问谁、按什么顺序问 —— 先查本机缓存、再查 hosts、最后才去问 DNS 服务器
- 管超时和重试 —— 第一台服务器没响应就换下一台,等到期还不行就告诉程序"查不到"
(第一张图左边那半就是它。)
为什么要专门有这么一层? 因为每个想上网的程序都不该重复造这套轮子。浏览器、ping、Java 的 InetAddress、系统的自动更新——它们统统是把这个域名丢给解析模块,然后等结果。
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
可以列好几个。 解析模块的规矩是:先问第一个,超时了才问第二个。所以第一个填错了(比如填了个不存在的地址),你的网页会先卡几秒才出去——"上网慢"有时候慢在这里。
家里的情况通常是这样的:
你的电脑 ──问──► 路由器(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 自己接着跑,你的电脑一概不知。
为什么是"你"能发递归,根服务器却不能
这两个问题的答案是同一个:代价由谁承担。
- 本地 DNS 必须支持递归,因为它是为客户端服务的——全世界的电脑配置水平参差不齐,指望每台电脑自己从根开始迭代问是不现实的
- 根服务器拒绝递归,因为它扛不住——全世界所有解析器都来问它,它只做最省力的活:告诉你
.com归谁管,然后你自己去
这个分工正是 3.21 那句"中间层越无知,可维护性越高"的另一面:越靠近顶层的服务器,做的活越少、处理的数量越大。
DNS 报文头里有两个专门的比特:
- RD(Recursion Desired) —— 请求里由你填:
1= "帮我查到底" - RA(Recursion Available) —— 响应里由服务器填:
1= "我支持递归"
所以你问根服务器时,就算填了 RD=1,它回的 RA 也常常是 0——等于礼貌地告诉你"这事我不管"。这个细节在抓包里一眼就能看见。
递归的另一重代价:缓存就是它的命
本地 DNS 为什么能把"三趟"跑得很快?因为它记得住。
| 情况 | 耗时量级 | 发生什么 |
|---|---|---|
| 缓存命中 | 亚毫秒级 | 直接回你,一步不出门 |
| 缓存未命中(冷查询) | 几百毫秒 | 真的从根开始问三趟 |
这就是"首次访问某网站慢、之后再打开就快"的底层原因(3.21 提过,本节给数字)。
反过来说:如果一个域名从没被任何人查过,本地 DNS 也没缓存,那它就得从根一路问下来——这段时间你是干等的,且解析模块还设了超时,超了它可能就换下一台服务器重来。
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:看解析模块和资源记录
-
看清解析模块手里的配置(本节第一步)
ipconfig /all找「DNS 服务器」那几行——这就是解析模块的"问询名单",顺序即优先级。家里一般写着路由器的地址(192.168.1.1)。 -
看它缓存了些什么(资源记录的实物)
ipconfig /displaydns3.21 看过一遍,这次换个读法:每一段的A (主机) 记录下面都有一行TTL——那就是本节讲的 TTL 字段,正在倒计时。往下翻还能看到CNAME 记录——五段式的实物就在眼前。 -
单条查询看全五段(本节最直接的一步)
nslookup -type=a www.baidu.com nslookup -type=ns baidu.com nslookup -type=mx baidu.com三条命令问同一台服务器,要的只是不同的 Type——回来的答案 RDATA 里装的东西完全不同。这就是"五段式里只有最后一段在变"的实物证据。 -
换个角度理解"问谁"(顺带证明解析模块的存在)
nslookup www.baidu.com nslookup www.baidu.com 8.8.8.8第一条问你配置的那台,第二条强行问 Google 的公共 DNS。注意:nslookup是自己实现了一套查询逻辑的,它绕过了系统的解析模块——这也是为什么它看不到 hosts(收 3.21 那个实验)。 -
看"根不做递归"长什么样(本节最有意思的一步) ``` nslookup
server 198.41.0.4 www.baidu.com
``198.41.0.4` 是根域名服务器(a.root-servers.net)的地址之一。向它发一个普通的查询(RD=1),它的反应通常是下面三种之一: - 回 REFUSED(拒绝服务)
- 回一个空的应答
- 只给你
.com的 NS 记录(线索)
三种结果都指向同一件事:根服务器不做递归。 它只给你线索,剩下的路得自己走。
(看完记得 exit 退出交互模式,并把 server 改回默认。)
- 30 秒实验:一冷一热,感受缓存的差距
nslookup www.baidu.com ← 记下耗时感受(快)再找一个从没访问过的域名:nslookup www.wikipedia.org ← 冷查询,可能明显慢一拍冷热差别就是"缓存命中 vs 从根一路问下去"的直观体感。家里宽带几百毫秒不明显,企业网络或跨境域名上会非常明显。
向根服务器发查询属于借用公共资源,偶尔看一眼原理没问题,千万别写成脚本循环发——那属于滥用,会被根服务器侧的防护拦掉,也可能被运营商注意到。看明白原理就收手。
七、常见误区
- ❌ "DNS 解析模块就是本地 DNS 服务器" → 一个在你电脑里(软件部件)、一个在网络上(服务器);前者是办事员,后者是档案馆
- ❌ "浏览器自己会查域名" → 浏览器只是调用解析模块,自己不实现那套逻辑(少数浏览器内置 DoH 是例外)
- ❌ "
nslookup的结果和浏览器完全一样" →nslookup绕过了系统解析模块,所以它不看 hosts、也不只用系统配置的那台服务器(3.21 那个 hosts 实验就是靠这一点成立的) - ❌ "一条 DNS 记录就是'域名 → IP'" → 那是 A 记录的样子;五段式(Name/Type/Class/TTL/RDATA) 才是通用格式,RDATA 里可以放域名、文字、甚至优先级数字
- ❌ "TTL 是缓存服务器的设置" → TTL 是记录自带的字段;各级缓存拿到后各自倒计时
- ❌ "递归查询是全流程都叫递归" → 递归只到本地 DNS 为止。本地 DNS 问根、问顶级域、问权威,那三段全是迭代
- ❌ "根服务器会帮你查出 IP" → 根只给线索(
.com归谁管),且拒绝递归;答案只有权威服务器才有 - ❌ "解析慢就是网络慢" → 也可能是解析模块配的第一台 DNS 服务器超时了,正在等它超时后换第二台
- ❌ "改了解析立刻生效" → 收 3.21:各级缓存按 TTL 过期;正确做法是先把 TTL 改小再动 IP
- ❌ "DNS 只存在于网络上" → 你电脑里就有一整套:解析模块 + 缓存 + hosts 文件
八、动手自测
- DHCP 和 DNS 都在"自动获取地址",区别在哪?
- "DNS 解析模块"和"本地 DNS 服务器"分别住在哪、各干什么?
- 解析模块出门问 DNS 之前,会先在本地查哪两样东西?
- 一条资源记录有哪五段?哪一段的内容会随类型改变?
- TTL 是谁定的?改 IP 之前为什么要先动它?
- 递归查询和迭代查询,分界线划在网络的哪个位置?
- 为什么根服务器不做递归?
nslookup为什么看不到 hosts 文件里的内容?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 是解析模块在"本机阶段"才查的东西。这正好证明两者的来源和路径是分开的。
⑨ 依次用:先问第一台,超时才换第二台。所以第一台填错(或响应很慢)时,表现为"上网前几秒卡住"——不是网速问题,是在等超时。
九、下一步学什么
- ☑ 3.23(按教材顺序) ✅ 已出——对必要的设置进行自动设置(DHCP):本节回答了"别人在哪",可"自己是谁"是谁在配?就是它——一套能下发 IP 之外一长串设置的配置框架,还带着租期和两道续租闹钟。点此接着学。
- ☐ 3.24(按教材顺序) —— 报个标题接着走:按教材脉络,第三章剩下的部分大概率是 HTTP 与网页浏览(应用层的下一个主角)、其他应用层协议,或 第三章小结。等你报标题。
相关笔记
- 对必要的设置进行自动设置(DHCP) —— 下一节:那个分岔表的另一半;本节末尾"DHCP 先发下 DNS 地址(option 6),解析模块才有问询名单",正是它负责的事
- 网络的电话簿(域名解析、主机名、DNS) —— 上一节:电话簿的全局结构(域名怎么读、DNS 为什么分三层);本节是它的执行细节(记录格式、解析模块、递归边界)
- 连接网络的过程(IP地址的设置) —— 四件套的第四件「DNS 服务器」;本节讲了这条配置怎么被解析模块使用(依次问、超时才换下一台)
- 只对传输给应用程序的数据进行分发(UDP) —— 每次"单趟问答"都是一个独立 UDP 数据报;这正是数据报"保留边界"的典型用法
- 根据端口号分配数据到应用程序(端口号、已知端口号) ——
53这个已知端口的出处;本节把"查询走 UDP、大响应走 TCP"用在了具体流程里 - 接收和传输数据的规则(使用TCP/IP进行通信) —— 流水线第 9 步:拿到 IP 之后才开始三次握手;解析跟建连接是两件事
- 为驱动应用程序而做准备的网络分层(传输层与应用层) —— DNS 是应用层协议;本节讲的是这个应用层协议怎么被本机调用
- 各种网络之间的通用语言(TCP/IP) —— TCP/IP 模型里 DNS 的位置(应用层)
- 是谁在负责收发数据(应用程序、P2P应用) —— "电脑本身不会上网、程序才会上网";DNS 查询正是程序发起的一次请求
- 网络基础 ——
InetAddress.getByName()就是解析模块在 Java 里的调用入口;UnknownHostException是解析模块说"查不到这个名字"