你可能从来没想过这么一个问题:我在浏览器地址栏里敲下 www.baidu.com,回车,网页就出来了。可网卡和路由器不认识"baidu",它们只认一串像 115.239.210.27 这样的 IP 地址。那么问题来了——人类友好的名字"www.baidu.com ",是怎么变成机器眼里那串数字的?反过来,你的机器既不知道对面活没活着,也不知道我发的包是不是在半路被扔了,它又是怎么得到回音的?

这一题的两半,分别由两个协议来解答:一个叫 DNS,负责"把域名翻译成 IP";一个叫 ICMP,负责"在网络层通报错误、做连通性诊断"。它们一个在应用层跑腿,一个在网络层当跑堂,看似毫不相干,却恰好凑成了我们上网时最常用的两个动作——打开网页、ping 一下通不通。今天这一讲,就把这两位掰开揉碎讲透。你学完会发现,那些面试里被反复刁难的"经典坑",其实都有非常清晰的底层解释。

在往下读之前,我默认你对下面的东西有概念,没有也不用慌,这里只做一句话铺垫:

  • IP 地址与端口:IP 确定"哪台主机",端口确定"主机上的哪个程序"。这俩是传输层的亲儿子,后面"ping 没有端口"那个坑全靠它来判断。
  • IP 数据报 / TTL:网络层传输的基本单位,TTL 是 IP 包头部里的一个字段,每过一个路由器减一。注意一会儿你还会在 DNS 里看到另一个也叫 TTL 的东西,两者千万别搞混,我会专门拎出来讲。
  • TCP/IP 四层模型:应用层、传输层、网络层、网络接口层。DNS 住在应用层,ICMP 住在网络层——位置是这两个协议一系列"脾气"的根源。

DNS 是什么:从 hosts 到一整套域名系统

DNS(Domain Name System,域名系统),简单说就是一整套"从域名映射到 IP"的系统。讲它之前,得先回顾一下"没有 DNs 的日子"人是怎么上网的,不然你不会懂它为什么非出现不可。

一切的起点:IP 太难记,于是有了主机名和 hosts 文件

TCP/IP 世界里,定位一台主机上的一个程序,靠的是 IP 地址 + 端口号 这对组合。麻烦在于:IP 地址是一串数字,像 115.239.210.27,人脑记几个还好,记成百上千个谁都记不住。于是人们发明了一个东西叫主机名(hostname)——它是一个字符串,比如 mail、web,比数字好记得多。然后,用一个叫 hosts 文件的描述文件,把"主机名"和"IP 地址"的对应关系一条条写下来。我们现在的计算机上仍然保留着这个文件,Linux 下可以用 cat /etc/hosts 查看,内容大致长这样:

# 每行:IP 地址        主机名
127.0.0.1            localhost
::1                  localhost
192.168.1.10         my-server

在互联网刚起步的年代,这个 hosts 文件由**互连网信息中心(SRI-NIC)**统一管理。问题很快出现了:如果有一台新计算机要接入网络,或者某台计算机的 IP 变了,都得跑到信息中心去申请"改文件";其他所有计算机还要定期去"下载新版本"才能正确上网。你想想这有多折磨人——全网节奏被一个中心牵着走,改慢一点,全世界都上不了正确的主机。

DNS 的诞生:把"中心管文件"换成"分布式查询"

大家受不了这种集中式的低效,便产生了 DNS(域名系统)。它的思路彻底反转了:

  • 每个组织自己的系统管理机构,只维护自己系统内每台主机的"IP 与主机名对应关系",注册到本地的数据库里;
  • 新计算机接入时,只需在自己的组织内做一次注册,不必通知全世界;
  • 用户输入域名时,自动向 DNS 服务器发起查询,由服务器检索数据库,把对应的 IP 返回给你。

你看,核心变化是"从一个人人下载的大文件",变成了"一套按组织分布式存放、按需查询的数据库"。这就是 DNS 的底层哲学:去中心化、按域划分、谁的数据谁负责。这个"分布式 + 分层"的特性,是后面理解域名树和递归/迭代查询的总开关。

一个小提醒:hosts 文件今天还活着,而且优先级很高

你可能会想,既然 DNS 这么先进,以前的 hosts 文件是不是就该淘汰了?并没有。直到今天,在域名解析的过程中,操作系统依然会优先去查 hosts 文件,查不到才走 DNS。 这也是为什么很多开发者喜欢往 hosts 里临时写一条"某域名 → 某测试 IP",用来把线上流量导到自己的开发环境;也是为什么某些网站建议把解析结果写进 hosts 来"防插队"。这条"本地优先"的规则非常重要,等我们讲到 DNS 缓存那一节,你会看到一个更完整的查询顺序。

域名:一台主机的"分层门牌号"

有了 DNS 系统,接下来就得给"名字本身"定个规矩。域名(domain name) 是用来识别主机名称以及主机所属组织机构的一种分层结构的名称。它不是随便一串字符,而是有明确层级、用点 . 连接的。

以 www.baidu.com 为例,我们把它从右往左拆开看:

www.baidu.com
   │     │    └── com     :顶级域(Top-Level Domain,小编也常称"一级域名")
   │     └──────── baidu  :二级域(公司的名字,如"百度")
   └────────────── www    :主机名 / 习惯用法(常指"这台机提供 Web 服务")
  • com:顶级域(Top Level Domain,TLD),表示"这是个企业域名"。同级的还有 net(网络提供商)、org(非营利组织)、edu(教育机构)等等。这里有个命名上的小坑要提醒你:很多中文教材习惯把顶级域直接叫"一级域名",所以你看资料时,"一级域名"和"顶级域"指的是同一个东西——就是最右边那个段。
  • baidu:二级域(Second-Level Domain,SLD),通常是公司名或组织名。你在域名注册商那里买到的,绝大多数就是这个二级域(比如 baidu.com、taobao.com)。
  • www:严格说它一个"子域/主机名"的角色。它其实只是当年的一种习惯用法——早期人们为了说明"这台机跑什么协议",喜欢把主机名命名成 ftp.xxx、www.xxx 这种格式,www 就是想表达"这台机提供 Web(HTTP)服务"。所以 www 跟 ftp、mail 一样,只是约定俗成,协议不同,并不是域名结构里的强制层级。很多网站现在把 www 当别名(CNAME,稍后讲),甚至干脆不用 www。

一个域名结构,本质上就是一棵从右往左越来越具体的树。这棵树长什么样子,直接决定了解析时"该问谁",我们接着往下看。

域名的树状结构:根、顶级、权威各司其职

把视角拉开,整个互联网的域名呈现出一棵倒挂的树状结构。树的形态是这样:

                    .            (根域 root,就一个点,代表"最顶端")
                ┌────┴────┐
             .com       .cn     (顶级域 TLD)
              │          │
           baidu      taobao    (二级域 SLD,企业自己管)
           ┌─┴─┐
         www   api              (三级域 / 主机名)

节点讲解

  • 根域(root):树的最顶端,用点 . 表示。它下面是 com、net、cn 这些通用的顶级域,以及 uk、jp 这类国家域。全世界有 13 组根域名服务器(注意是"13 组",不是 13 台!每组都用 a.root-servers.net 到 m.root-servers.net 这样的名字,本质是分布在全世界非常多台物理机器组成的集群,用 Anycast 对外呈现成一个逻辑地址)。根服务器不负责具体解析某个域名,它只回答一句话:"某个顶级域归谁管。"
  • 顶级域服务器(TLD Server):管理某个顶级域的名单,比如管理 .com 的服务器知道"所有 .com 二级域的权威服务器在哪"。注意命名上的一点:课件里常把 com 称作"一级域名",指的是"顶级域",它对应的服务节点叫"顶级域服务器",你可能看到的表述有"一级域名服务器 / 顶级域名服务器",是一个东西。
  • 权威域名服务器(Authoritative Name Server):真正"说了算"的那台服务器。它持有某个具体域名(比如 baidu.com)自己的区域文件(zone file),里面就是"www.baidu.com → IP"这类真实记录。只有它返回的数据才是权威的,报文里会带一个专门的标志位 AA(Authoritative Answer,权威应答=1),表示"这条是我家注册的真实数据,不是我转发/缓存的"。
  • 本地域名服务器(Local DNS / Resolver):你的电脑配置的 DNS 服务器,通常由运营商或路由器提供(比如 114.114.114.114)。它是个"中间人 + 缓存",你发的所有查询请求先到它这儿,它会帮你跑腿,还会把查到的结果缓存起来。

一句话记住分工:根服务器告诉你"顶级域找谁",顶级服务器告诉你"二级域找谁",权威服务器给出最终 IP,而本地服务器负责替你跑完全程。

递归查询 vs 迭代查询

树搭好了,"问路"的方式也有讲究,这是面试最爱考的点。先明确两个术语:

  • 递归查询(Recursive Query):你只问一次,剩下的"跑腿"全交给对方,对方负责一层层问下去,最后把最终答案交给你。特点是"一问到底",对发起方省心,对接收方费劲。
  • 迭代查询(Iterative Query):被问到的那台服务器不替你跑腿,只告诉你"下一步该问谁",你自己拿着这条线索接着问。特点是"问一步、走一步",每台服务器只负担极小的工作量。

实际的域名解析,是两种方式结合使用的,分工非常清晰:

  • 你的电脑 → 本地 DNS 服务器:用的是递归查询。电脑把域名丢给本地 DNS,就等着拿结果,中间层层询问全是本地 DNS 的事。
  • 本地 DNS 服务器 → 根/顶级/权威服务器:用的是迭代查询。根服务器不会帮本地 DNS 跑腿,它只回一句"你去找 .com 的顶级服务器";顶级服务器也只回"你去找 baidu.com 的权威服务器",最后本地 DNS 从权威服务器拿到 IP 才收手。

为什么中间层级必须用迭代、不能让根服务器去递归?因为根服务器是全球基础设施,负载极其敏感。如果根服务器也去递归,它就得为每一个查询"挂起等待"下面一层层服务器的结果,需要维护大量查询状态,极易过载。所以规定根服务器只做迭代——每来一个请求只回一句话就完事,负载被摊到海量的本地 DNS 身上。这也是一个非常经典的设计取舍:把压力放在数量多、可扩展的本地层,把轻负载留给数量少、不可替换的核心层。

我们可以用一个 ASCII 图把最常见的完整流程画出来(以下 www.baidu.com 为例):

① 你的电脑 ──递归查询──▶ 本地DNS ──迭代──▶ 根服务器(.)      返回: .com 归谁管
                                  ├──迭代──▶ .com顶级服务器  返回: baidu.com权威服在谁
                                  └──迭代──▶ baidu.com权威服  返回: 真正IP  ← 拿到答案
                                      │
② 本地DNS 把答案缓存起来, 再 ──递归回应──▶ 你的电脑  (拿到 www.baidu.com 的 IP)

画成文字脚本就是:

你的电脑 → 本地DNS:帮我查 www.baidu.com                          (递归)
本地DNS  → 根服务器:www.baidu.com 的 IP 是什么?
根服务器  ← 回:我不知道,但 .com 顶级域服务器是 xxx,你去问它      (迭代)
本地DNS  → .com顶级服务器:www.baidu.com 的 IP 是什么?
.com顶级  ← 回:我不知道,但 baidu.com 的权威服务器是 yyy,你去问它  (迭代)
本地DNS  → baidu.com权威服务器:www.baidu.com 的 IP 是什么?
权威服务器 ← 回:www.baidu.com 对应 115.239.210.27(权威应答 AA=1)(迭代)
本地DNS  → 你的电脑:CDN 上 www.baidu.com 的 IP 是 115.239.210.27 (递归完成)

用 dig 亲手拆解一次域名解析

概念讲完了,动手实操最有感觉。Linux 上最得力的 DNS 分析工具是 dig,它能非常清晰地展示"我提了什么问、服务器回了什么"。某些发行版(如 CentOS/RHEL 7)需要先装一下:

yum install bind-utils

dig 这个命令来自 bind-utils 包。装好之后,直接对域名发起查询:

dig www.baidu.com

典型的输出长这样(我用一份真实抓取的样例来解释结构):

; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7_5.1 <<>> www.baidu.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41628
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;www.baidu.com.         IN A

;; ANSWER SECTION:
www.baidu.com.       1057   IN   CNAME   www.a.shifen.com.
www.a.shifen.com.     40    IN   A       115.239.210.27
www.a.shifen.com.     40    IN   A       115.239.211.112

;; Query time: 0 msec
;; SERVER: 100.100.2.136#53(100.100.2.136)
;; WHEN: Wed Sep 26 00:05:25 CST 2018
;; MSG SIZE  rcvd: 90

我们逐段拆开:

  1. 第一行是你所用 dig 指令的版本号,以及本次查询的目标域名。
  2. HEADER(头部) 是服务器返回的"总览",关键看 status 参数:NOERROR 表示查询成功(其他常见状态还有 NXDOMAIN=域名不存在、SERVFAIL=服务器故障等)。
  3. QUESTION SECTION(问题段):;www.baidu.com. IN A —— 我这次问的是"www.baidu.com 的 A 记录"。这里的 IN 是 INTERNET 类别,A 是记录类型(Address,地址记录,表示要取 IPv4 地址)。
  4. ANSWER SECTION(回答段):这是本次的核心。三行其实揭示了一个别名解析链:
    • 第一行 www.baidu.com. 1057 IN CNAME www.a.shifen.com. 说明 www.baidu.com 其实是一个 CNAME(别名记录),它真正指向 www.a.shifen.com;
    • 后面两行 www.a.shifen.com. 40 IN A 115.239.210.27 和 ... 115.239.211.112,则是把真实主机解析出了两个 IP。之所以有两个,是因为百度(以及绝大多数大站)都做了负载均衡——同一域名对应多台服务器,用户会被分流到不同机器。顺带说一句,shifen 是百度的域名体系,这套 CNAME→CDN/负载均衡的玩法非常常见。
  5. Query time:本次查询耗时(0 msec 说明命中缓存了)。
  6. SERVER:响应你查询的 DNS 服务器地址,#53 是 DNS 服务的默认端口 53。
  7. MSG SIZE:本次响应报文大小(90 字节)。

注意一个细节:上面答案里,A 记录后面那个 1057 和 40,就是这条记录的 TTL(缓存时长)——同一个域名 www.baidu.com 被解析出来,不同记录带的值还能不同。这个"TTL"我们马上单独讲,千万别和 IP 包里的 TTL 混了。

DNS 记录类型:A、CNAME、NS 到底在说什么

dig 的回答里已经冒出了 A 和 CNAME 两种记录,再配合前面的 NS,我们把最常见的几种资源记录(Resource Record,RR) 一次讲清楚。它们其实就是"DNS 数据库这张大表"里的不同列:

记录类型全称 / 含义作用
AAddress,地址记录把域名映射成一个 IPv4 地址(如 www.baidu.com → 115.239.210.27),最常用
AAAA四倍 A把域名映射成一个 IPv6 地址
CNAMECanonical Name,别名记录把"别名"指向"正经的名字",如 www.baidu.com 是 www.a.shifen.com 的别名。好处是换后端 IP 时只改一处
NSName Server,名称服务器记录声明"谁是这个域的权威服务器",如 baidu.com 的 NS 是 ns1.baidu.com。找权威服务器靠它
MXMail Exchange,邮件交换记录指定该域名的邮件服务器在哪,收发邮件用
PTRPointer,指针记录反向映射:由 IP 找域名,跟 A 记录反着来
TXT文本记录放一段任意文本,常用于做域名所有权验证、SPF 反垃圾邮件等

Record 类型里有个非常容易忽略但重要的点:CNAME 和 A 记录是"换皮"关系。www.baidu.com 本身没有 A 记录,它是 CNAME 指向 www.a.shifen.com,真正的 A 记录挂在后者身上。所以你在做 DNS 排查时,看到一个域名"只有 CNAME 没有 A",是完全正常的——它把"真实 IP"藏在了被指向的那台主机上。反过来,RFC 规定:给定主机名下,CNAME 记录不应该和其他记录类型混在同一个名字下,因为 CNAME 一旦存在,别的类型就不该再为这个名字定义其他含义。

两个 TTL,别搞混:DNS 的"缓存寿命" vs IP 的"跳数寿命"

名字一样,含义天差地别,这是本文必须给你设的防混淆护栏。网络里有两种 TTL,缩写碰巧完全相同,但毫无关系:

第一种,DNS 记录里的 TTL。 它表示"这条解析结果可以在缓存里存活多少秒"。比如前面答案里 A 记录 40,意思是"这 IP 记住 40 秒,过期后就该重新问权威服务器"。DNS 的这些 TTL 也叫"缓存寿命"。本地 DNS 也好、你的操作系统也好,都会严格按照它来决定缓存多久、何时必须重新解析。这是前面那行数字 40、1057 的由来。

第二种,IP 包头部里的 TTL。 它表示"这个数据包最多还能经过多少跳(hop)路由器"。IP 报文每过一层路由器,TTL 减一;减到 0 时路由器直接把它丢弃,并向源头发送一个 ICMP 错误报文(这正是 traceroute 能工作的基础,后面细讲)。它是用来防止数据包在网络上无限兜圈的——举个例子,如果 A、B、C 三台路由器配置出错形成环路,一个包如果 TTL 不会递减,就会永远在环路上打转,把网络带宽耗尽,TTL 机制从根本上掐死了这种"僵尸包"。

两个对照一下记:

THING出现在哪单位作用
DNS 的 TTLDNS 报文记录字段秒决定缓存多久,过期重新解析
IP 的 TTLIP 报文头部跳数每过一跳减一,归零即丢,防止环路

所以当你听到别人说"TTL=64",先问一句他是说 DNS 还是 IP——这俩的运维含义完全不是一回事。这也是面试题里经常埋的一个"陷阱点",你分得清,就已经赢过很多人了。

DNS 缓存与 hosts:一条"本地优先"的完整查询链

DNS 查询能这么快、这么大流量下还能扛住,靠的正是层层缓存。值得刻意强调的是,缓存的顺序非常讲究,我把它画成一副"从最里往外查"的图:

你输入 www.baidu.com
    │
    ① 浏览器缓存  ──有→ 直接用, 结束
    │ 无
    ② 操作系统 hosts文件 ──有→ 直接映射, 结束   (hosts 永远最先被信任)
    │ 无
    ③ 操作系统级 DNS 缓存 ──有→ 直接用, 结束
    │ 无
    ④ 本地DNS服务器(Resolver) 缓存 ──有→ 返回, 结束
    │ 无
    ⑤ 递归+迭代查询根/顶级/权威服务器拿到结果, 各层按 TTL 缓存后返回

把这条链记住,很多"奇怪的上网现象"瞬间就有了解释:

  • 为什么改完 hosts 立刻生效、改 DNS 要等一会儿? 因为 hosts 是在操作系统层被最优先检查的,几乎不需要网络请求;而 DNS 解析有各级 TTL,改完权威服务器上的记录,下游缓存到期前拿到的仍是旧 IP。
  • 为什么换新网站第一次打开慢、之后快? 第一次要真正走 ⑤ 的完整链路;之后各级缓存都在,几毫秒就回了。
  • 为什么公司内网能访问、外网不行? 很可能内网域名写在 hosts/内网 DNS 里,解析被命中;外网域名解析链出问题才失败。

不同系统查看缓存的方式也不一样:

  • Windows:ipconfig /displaydns 可以查看系统级别的 DNS 缓存;想清空用 ipconfig /flushdns。
  • Linux:传统上没有统一的系统级 DNS 缓存(早期全靠 nscd,后来 systemd 自带的 systemd-resolved)。是否缓存、怎么清,取决于你的发行版用的是哪种解析器(具体在 systemd-resolve --statistics 这类命令能看到)。
  • 浏览器:各自还有一层自己的 DNS 缓存,Chrome/Edge 的可以在 chrome://net-internals/#dns 里查看和清空。

这里再抖一个你迟早会撞上的坑:"改个 hosts 无效"。很多情况下你是把域名写进 /etc/hosts 了,但应用层(比如浏览器)或某些程序仍用自己内部的 DNS cache,或你的系统根本是优先走了某个硬编码的解析器,导致 hosts 没"插上队"。排查顺序一般就是"清浏览器缓存 + 清系统缓存 + 确认 hosts 语法没写错 + 确认没被代理/隐私 DNS(DoH)绕过"。尤其是隐私 DNS,它可能绕过 hosts 和本地缓存直接走加密查询。

从浏览器输入 URL 说起:一次完整的解析 + 连接

不夸张地说,"浏览器里输入 URL 后发生了什么"是网络面试里出现率最高的开放题。它没有唯一标准答案,越详细越好,而且我们前面讲的所有东西都会在这里串联起来。我按一次真实的访问流程给你完整串一遍:

  1. 输入并敲回车:浏览器拿到 URL http://www.baidu.com/,拆出协议(http)、主机(www.baidu.com)、路径(/)。
  2. 查本地:浏览器依次查自己的缓存和系统 hosts / 系统 DNS 缓存。命中就直接用 IP,未命中才继续。
  3. 走 DNS 解析:把 www.baidu.com 交给本地 DNS,经历前面讲的递归+迭代,最终拿到真实 IP(比如 115.239.210.27)。
  4. 建立 TCP 连接(三次握手):浏览器用这个 IP + 端口号 80(HTTPS 是 443)与目标服务器建立 TCP 连接。
  5. (若有 HTTPS)TLS 握手:协商加密、校验证书,建立安全通道。
  6. 发送 HTTP 请求:浏览器发 GET / HTTP/1.1(或 HTTP/2/3)及请求头。
  7. 服务器响应:返回 HTML 页面及各种资源。浏览器一边收一边解析渲染,同时会对页面里的图片、CSS、脚本发起新的(很多已被缓存命中的)DNS + 连接请求。
  8. 断开或复用连接:短连接关闭,长连接(Keep-Alive)则由连接池复用。

这道题的深度弹性很大:往细里挖,每一步还能再展开成一整篇文章(三次握手、TLS 证书链、HTTP 状态码、Nagle/延迟 ACK……)。作为一个面试练习,你只要能一口气把上面的链条说清楚并点出每一步涉及的协议,就已经相当出彩了。

ICMP 是什么:网络层的"质检和跑堂"

CPU 的另一半——ICMP(Internet Control Message Protocol,互联网控制报文协议) 是时候登场了。它是个网络层协议,解决的问题非常朴素:一个刚搭好的网络,怎么验证它通不通?

我们得先从 IP 协议的一个"缺陷"说起。IP 协议本身并不提供可靠传输——它只负责尽力把数据包送出去,至于中途是不是丢包、为什么丢包、有没有到目的地,IP 统统不管。这就像你寄了一份包裹,快递公司(IP)说"我尽量送",但既不给你回执,也不告诉你货坏没坏在半路。传输层那些 TCP 的确认、重传,正是为补这个洞而生。

那么问题来了:传输层能感知丢包,可它只知道"一个包没了",不知道到底为什么没。是目标关机了?还是网络断了一段?还是 TTL 用尽被丢?这时候就需要一个"跑堂"的角色,在 IP 层帮忙通报。ICMP 就是干这个的。它的主要功能概括为两条:

  • 确认 IP 包是否成功到达目标地址(用诊断查询类报文,比如 echoes);
  • 通知发送过程中 IP 包被丢弃的原因(用错误报告类报文,比如"不可达""超时")。

这里有几个要点必须讲清楚,它们是理解 ICMP 的一把钥匙:

  1. ICMP 是基于 IP 协议工作的,但它本身不是传输层的功能。传输层指的是 TCP/UDP 这种面向应用进程传输数据的协议;ICMP 并不为应用程序"搬运业务数据",它只传递"网络层的控制/诊断/错误信息",因此人们仍把它归为网络层协议。
  2. ICMP 只能搭配 IPv4 使用。如果走 IPv6,对应的是 ICMPv6,二者报文格式、类型号都有差异,不要混着说。IPv6 里连邻居发现、地址重复检测这类活儿,也都要靠 ICMPv6 完成,它在 IPv6 里的地位比 IPv4 里的 ICMP 更高。
  3. ICMP 报文承载着信息,但它"不负责传数据"。注意这个表述要抠准:ICMP 错误报文里确实会夹带一部分导致出错的原始包头部(供发送方定位问题),ping 也会携带一小段负载,但ICMP 不是用来替应用层搬运业务的传输通道,它不建立端到端连接,也不提供可靠投递。所以你可以说"ICMP 不传输应用数据",却不能说"ICMP 报文里什么内容都不带"。

ICMP 的报文格式与两大分类

报文格式我们不必死磕每个字节(属于"选学",面试一般不问细节,问到也就聊聊分类和类型号),但整体结构值得了解。ICMP 报文大体长这样:

 0               8               16              24          (bit)
 ├───────────────┬───────────────┬───────────────┤
 │    类型 Type  │   代码 Code   │   校验和 Checksum     │
 ├───────────────┴───────────────┴───────────────┤
 │            (不同报文类型,这里内容不同)              │
 │    有的带 ID 和序号,有的带原始 IP 头和数据            │
 └──────────────────────────────────────────────┘
  • 类型(Type):报文是哪一类,决定了大方向。
  • 代码(Code):在某个大方向下细分的小原因。
  • 校验和(Checksum):校验完整性。
  • 之后的内容随类型而异,要么是诊断用的 ID/序号,要么是"被丢弃原始包的一部分"。

ICMP 报文大致分成两大类:

第一类:通知出错原因(错误报告)。这类报文是"跑堂"的核心职责,常见的有:

  • 类型 3 目标不可达(Destination Unreachable):分很多子代码,比如网络不可达、主机不可达、端口不可达等。traceroute 到达终点,就是靠"端口不可达"来判定"到头了"。
  • 类型 11 超时(Time Exceeded):典型是"TTL=0,包被丢弃"。这是 traceroute 能画出一跳一跳的根由。

第二类:诊断查询类(用于主动探测)。这里最著名的是:

  • 类型 8 回显请求(Echo Request) 和 类型 0 回显应答(Echo Reply):一问一答,组成 ping 的核心。我用一张 ASCII 图把它画直白:
   你的主机                                 对端主机
      │       ICMP Echo Request (type 8)          │
      │ ────────────────────────────────────────▶  │
      │         ICMP Echo Reply  (type 0)          │
      │ ◀────────────────────────────────────────  │
   记录往返时间 RTT,统计丢包

说明:ICMP 详细类型号(Echo Request=8、Echo Reply=0、Dest Unreachable=3、Time Exceeded=11、Redirect=5 等)是广为流传的标准取值,我建议你至少把最常用的几个类型 8 / 0 / 3 / 11 记住,面试和排障都用得上。

ping:最常用的连通性测试命令

ping 大概是 Linux 和 Windows 上都被人敲得最多的命里命令。它的原理一句话:发送 ICMP Echo Request,等待对端回一个 ICMP Echo Reply,靠这个一来一回验证"网络通不通",同时测量往返时间(RTT) 和看包里的 TTL。

ping www.baidu.com
PING www.a.shifen.com (115.239.210.27) 56(84) bytes of data.
64 bytes from 115.239.210.27: icmp_seq=1 ttl=54 time=12.3 ms
64 bytes from 115.239.210.27: icmp_seq=2 ttl=54 time=11.9 ms
...

几个细节值得点透:

  • ping 的参数是域名,不是 URL。这个坑在课件里被特意拎出来:很多人下意识 ping https://www.baidu.com/,那是错的。ping 只管"一台主机的 IP",所以传域名(DNS 会先解析成 IP)或直接传 IP(如 ping 8.8.8.8)都行,但别传完整 URL。这也是为什么 ping 一执行通常就会看到它已经把域名解析成了 IP(上面输出第一行就是)。
  • ping 不仅验证连通性,还会报告 RTT 和 TTL。RTT 是"一来一回"的毫秒数,越小说明链路越快;TTL(这里是 IP 的那个 TTL)是被对端减过之后的值,能侧面反映"离目标隔了多少跳"。比如 Linux 默认初始 TTL 常取 64,Windows 常取 128,如果回包 ttl=54,说明中间大约经过了 64-54=10 跳(这是粗估,因路径可能不均衡,谨慎一点用)。
  • ping 通 ≠ 服务可用。这点相当容易被误解。ping 只证明"目标主机的内核/协议栈还活着、并且放行 ICMP",绝不代表目标上那个 Web 服务、数据库服务是好的。一个服务进程挂了、端口没监听,只要内核还活着,ping 照样通。反过来,很多防火墙默认禁 ICMP,ping 不通也不代表一定连不上。所以 ping 常被定位成"网络连通的粗筛",具体服务是否可用要看对应的端口(比如 telnet host 80)。

那个著名的坑:ping 是什么端口?

面试官可能会笑着问你:"telnet 是 23 端口,ssh 是 22 端口,那 ping 是什么端口?"

千万小心,这是圈套。正确答案是:ping 没有端口。

端口(port)是传输层的概念,用来在同一台主机上区分"是给哪个程序/进程的数据"。而 ping 基于 ICMP,剥开每一层,它工作在网络层,根本不关心、也用不到端口这种东西。ICMP 报文里压根就没有"源端口/目的端口"这两个字段——它靠"类型 + 代码"来区分用途,而不是靠端口号。所以你既可以说"ping 没有端口号",也可以说"不能用端口号去给 ICMP 分类"。

用一句话当锚点:端口号是传输层(TCP/UDP)的身份证;ICMP 不归宿于传输层,它没有身份证。 反过来说,如果你能用 telnet/nc 去连某个端口、做完三次握手,那说明"某个应用层服务在这个端口上活着";而 ping 通只说明"这台机器的网络栈活着"。这两者切成两回事。这也是"ping 通但网站打不开"这种经典排障场景的底层解释——连接的建立依赖传输层和上层应用,ping 完全覆盖不到。

traceroute:看清通往对端的一台台路由器

traceroute(Windows 下叫 tracert)能打印出"你的程序从源主机到目标主机之间,经过了哪些路由器",每一台(每一跳)都列出 IP 和往返时间。它靠的正是 IP 包的 TTL 递减机制 + ICMP 错误报告这一黄金组合。原理值得仔细讲:

回忆一下:IP 包每经过一个路由器,头部 TTL 减一,减到 0,路由器就丢弃该包,并回一个 ICMP 类型 11(Time Exceeded,超时) 报文给源主机,同时带上"我这个路由器是谁"的信息。traceroute 正是利用这一点,故意把 TTL 从 1 开始,一点一点加:

traceroute 发 TTL=1 的包  → 第1台路由器 TTL变0丢弃, 回ICMP超时  → 记录 第1跳
traceroute 发 TTL=2 的包  → 第2台路由器 TTL变0丢弃, 回ICMP超时  → 记录 第2跳
traceroute 发 TTL=3 的包  → 第3台路由器 TTL变0丢弃, 回ICMP超时  → 记录 第3跳
  ......(一直加 TTL,直到抵达目标)
traceroute 发 到大目标 TTL 足够大 → 目标主机收到, 回 ICMP某种应答 → 判定路径结束

把这张图立起来看就是这样:

主机(traceroute)
   │   TTL=1 ────────▶ R1 ──  TTL=0! 丢弃  ──▶ 回ICMP TimeExceeded ──▶ 第1跳
   │   TTL=2 ────────▶ R1 ──▶ R2 ── TTL=0! 丢弃 ──▶ 回ICMP TimeExceeded ──▶ 第2跳
   │   TTL=3 ────────▶ R1 ──▶ R2 ──▶ R3 ── TTL=0! 丢弃 ──▶ 回ICMP TimeExceeded▶ 第3跳
   │   ...
   │   TTL=n ──── ... ────▶ 目标主机  ── 回 EchoReply / 端口不可达 ──▶ 到达, 结束

每次"探一探"默认发 3 个包,返回 3 个时间,所以输出里每行会有三个毫秒数。如果某跳没收到回应,就打印三个 *。

这里有一个必须讲清楚的平台差异(很多人长期混淆):不同操作系统 traceroute 用的"探测包"不一样。

  • Linux / macOS 的 traceroute:默认发的是 UDP 数据报,目的端口从 33434 开始逐渐增大。中间路由器因为 TTL 耗尽返回 ICMP 超时;而目标主机收到一个"端口不可达"的 UDP 时,会回一个 ICMP 类型 3 代码 3(端口不可达),traceroute 靠这个"端口不可达"来判定"已经到目标了",从而终止。也就是说,Linux 默认的探测包确实是 UDP,但它能画出路程,依赖的依然是 ICMP 超时报文。
  • Windows 的 tracert:探测包直接就是 ICMP Echo Request(跟 ping 一样),靠中间路由器回 ICMP 超时判断每一跳,最后靠目标回 ICMP Echo Reply 判定到达。

所以严格说,"traceroute 基于 ICMP 实现"这句话是成立的但需打个补丁:它核心依赖的路由日志(TTL 耗尽导致的 ICMP Time Exceeded)来自 ICMP,至于它自己发的探测包是用 UDP 还是 ICMP(乃至可选 TCP),因平台而异。理解到这一层,别人问你"traceroute 和 ping 有什么区别"时,你就能答出本质:

维度pingtraceroute
目的只测目标通不通、RTT 多少画出完整路径,定位中间哪跳慢了/断了
核心机制单发 ICMP Echo,等 Echo Reply递增 TTL,逼途每台路由器回 ICMP 超时
输出每包的 RTT 和丢包每一跳的 IP 和三个时间
探测包恒为 ICMP Echo RequestLinux/macOS 用 UDP、Windows 用 ICMP(可选 TCP),但都依赖 ICMP 超时

一个常见误判也要给你打预防针:traceroute 里看到 * * *,不代表网络断在这一跳。 很多运营商路由器出于安全或限流,会抑制 ICMP 超时报文(rate-limit 甚至直接不发),导致这一跳"失声"。如果后面几跳还能正常返回,说明路径本身没断,只是这台特定路由器不"报家门"而已。这是生产环境排障时最容易被吓到的一次乌龙。

结合排障场景:把 DNS、ICMP、TTL 用起来

学了一堆概念,最终要回到"能用上"。给你一个最典型的综合排障剧本:"网站打不开",用我们这一讲的知识一步步定位:

① 先 DNS 查解析:   dig www.site.com             → 看能不能解析出 IP?(DNS 问题?)
② 再 ping 通不通:  ping www.site.com            → 网络栈通不通?(网络问题?)
③ 再看能否连端口:  telnet www.site.com 80       → 服务端口通不通?(服务问题?)
④ 需要看路径:      traceroute www.site.com      → 到底卡在哪一跳?(路由问题?)

每一步对应一个"层",答案不同的组合会指向截然不同的原因。比如:

  • ①失败、②③也失败 → 多半是 DNS 配错或解析链出问题,先查 /etc/resolv.conf、本地 hosts、防火墙是否禁了 53 端口。
  • ①②通过但③失败 → 目标服务没监听该端口或被防火墙挡了,属于应用/端口问题,跟 DNS 无关。
  • ①通过、②失败、③异常 → 网络层出了问题,用 traceroute 盯到"从哪一跳开始 *",缩小范围。
  • 全程 TTL 很小又稳定 → 路径跳数多或某段链路差,可看 RTT 异常增大在拓扑哪一段。

用一句话收拢这一讲的知识:DNS 解决"去哪找"(域名→IP),ICMP 解决"到了没、为啥没到"(连通与错误通报),TTL 是其中反复出现的"寿命/跳数"坐标。 三者在一次次排障中配合得严丝合缝,也就解释了为什么把它们放在一个加餐里一起讲。

自测与思考题(带详解)

下面这些题目我都配了详细解答,建议你先自己默答一遍,再看答案——能讲清楚每题,这一讲才算真正装进脑子里。

1. 面试送命题:ping 是什么端口?为什么?

答案: ping 没有端口号。端口是传输层(TCP/UDP)的概念,用来区分同一主机上不同进程的数据;而 ping 基于 ICMP,iCmp 是网络层协议,报文结构里根本没有源端口/目的端口字段,它靠"类型 + 代码"表达含义。所以答"ping 没有端口"才对,答成"用 80/443"这类就进了圈套。这也是"ping 通但服务不可用"的根源——连通性和端口/服务的状态是两码事。

2. 递归查询和迭代查询的区别?实际中分别用在哪一段?

答案: 递归查询是"你只问一次,对方负责跑腿、返回最终答案",发起方省心、接收方费劲(要维护查询过程);迭代查询是"被问者不代劳,只告诉你下一步问谁",每台服务器只负担极小负载。实际分工是:主机到本地 DNS 用递归;本地 DNS 到根服务器、顶级域服务器、权威服务器用迭代。根服务器只能做迭代,否则全球根节点要维护海量查询状态,极易过载。

3. 报文中出现 AA 标志、RCODE NOERROR、记录 CNAME,分别说明什么?

答案: AA=1 表示该应答来自权威域名服务器,是其区域文件里的真实数据,不是缓存/转发;NOERROR 表示本次 DNS 查询成功、无错误;出现 CNAME 记录表示该域名是"别名",真正的 A/AAAA 地址要跟着 CNAME 指向的"正主"去找(比如 www.baidu.com 是 www.a.shifen.com 的别名)。三者合起来看,说明你拿到了一条由权威服务器给出的、成功的、带正向别名链的解析结果。

4. DNS 的 TTL 和 IP 的 TTL 一样吗?各自干嘛?

答案: 不一样,只是名字撞了。DNS 记录里的 TTL 以"秒"为单位,表示这条解析结果能缓存多久、到点就要重新问权威服务器;IP 报文头部的 TTL 以"跳数为单位",每过一个路由器减一,归零即被丢弃,用来防止数据包在环路里无限打转。运维里说"TTL=64"通常指后者(ICMP 回包里的跳数),说某条记录"TTL=600"则指前者(缓存寿命),务必分清。

5. 为什么说"ping 通不等应用可用、ping 不通也不一定连不上"?

答案: ping 只验证目标主机的网络层/协议栈是否存活并放行 ICMP,它探的是"机器有没有开机、网络通不通",不探任何应用服务。所以服务进程挂掉、端口没监听,只要内核还活着,ping 照样回包(ping 通≠可用)。反之,许多防火墙、云安全组默认丢弃 ICMP Echo,会直接挡掉 ping 报文,但这种丢弃并不等于 TCP/HTTP 也被禁,所以 ping 不通≠真的连不上。要用"端口连通性(如 telnet host 80)"或直接访问服务来确认应用层状态。

6. traceroute 为什么能"自己报出每一跳"?为什么 Linux 默认用 UDP 探测却仍说它基于 ICMP?

答案: 它利用"IP 包 TTL 每过一跳减一,归零时路由器丢弃并回 ICMP 类型 11 超时报文"的机制,故意把 TTL 从 1 递增着发探测包:TTL=1 让第一台路由器丢包报超时,TTL=2 让第二台……如此逐跳逼出中间每台路由器的身份和时间。"基于 ICMP"指的是它核心依赖 ICMP 超时(Time Exceeded)报文来绘制路径;而它自己发的探测包因平台而异——Linux/macOS 默认发 UDP(目的端口 33434 起),靠最后目标回 ICMP 类型 3 代码 3"端口不可达"来判定到达终点;Windows 的 tracert 则直接发 ICMP Echo。所以"基于 ICMP"这个说法对,但探测载体不是只有 ICMP。

7. 浏览器输入 URL 后,从 DNS 到显示页面,按顺序会发生哪些关键步骤?

答案(要点式): 浏览器解析出协议、主机、路径 → 依次查浏览器 DNS 缓存、系统 hosts/系统 DNS 缓存 → 未命中则交给本地 DNS 走"递归+迭代"解析拿到真实 IP → 用 IP+端口(HTTP 80 / HTTPS 443)与服务器建立 TCP 连接(三次握手)→(若是 HTTPS)再做 TLS 握手商密校验证书构建安全通道 → 发送 HTTP 请求(GET 等)→ 服务器返回 HTML 及各类资源,浏览器边收边解析渲染、对页面资源的子请求通常已有缓存命中或另起新连接 → 短连接关闭 / 长连接交给连接池复用。答得越能展开每步涉及的具体协议,越有说服力。

8.(动手题) 用一个 dig 命令把"本地 DNS 做了几次迭代查询、最后问到了哪台权威服务器、拿到了哪几条记录、TTL 多少"这些信息读出来。

答案(参考步骤): 核心用 dig +trace 域名 可看到逐级解析:它会依次列出根、顶级、权威各服务器给的回应(AUTHORITY 段里的 NS 与对应 IP),最后从权威服务器的 ANSWER 段里"权威"地给到最终 A/CNAME/AAAA 记录及各自的 TTL。若只想看最简解析结果用 dig www.baidu.com +short;想看回答详情用 dig www.baidu.com;想看走了哪几步用 dig +trace www.baidu.com。读取时应关注 ANSWER 段的记录类型与 TTL(缓存寿命)、以及 AUTHORITY 段给出的下一跳权威/NS 服务器线索——我们前面讲的"递归+迭代、CNAME 链、TTL",都能在一次 +trace 输出里找到实证。


到此,我们走完了一堂"基石型"加餐。你手里现在攥着两条主线:DNS 负责把"人类可读的域名"翻译成"机器可读的 IP",它由 hosts 演进而成,是全世界最大的一张分布式"大表",靠树状分层、递归+迭代查询和层层缓存来支撑海量流量,当中对流着 A、CNAME、NS 等记录,藏着两种 TTL 的混淆暗礁;ICMP 则是网络层的质检员与跑堂,用错误报告类报文汇报"到没到、为何丢",用诊断类报文支撑起 ping 与 traceroute 两大神器,而"ping 没有端口"这个坑,恰恰是理解"网络层 ≠ 传输层"最好的试金石。

这两条线一个活在应用层、一个活在网络层,却在浏览器、ping、traceroute 这些日常指令里完美交汇。下次你敲下 ping www.bing.com,不妨在心里同步走一遍 DNS 解析的层级、ICMP 的报文、以及 TTL 那一角的递减身影——网络其实没那么神秘,它不过是一层层讲规矩的"问路与回话"。把这一讲的图在脑子里画熟,往后无论是面试、排障还是理解更复杂的网络编程,你都会脚下有根。这一讲先到这儿,下一讲我们再顺着"协议栈"往下钻,把网络编程真正落到 socket 的代码上。