Skip to content

01 · 分层模型与一次请求的一生 ​

这是网络模块的总纲。先看懂这篇的"封装-解封装"过程,后面四篇才有地方挂。

一句话本质 ​

数据从上往下走,每层加一个头(封装);到了对方从下往上走,每层拆一个头(解封装)。网络的一切复杂度,都在这些头里。

生活类比:寄快递的层层包装 ​

你写的信(应用层数据)
  v 装进信封,写上"收件人、寄件人"(加 TCP 头)
  v 装进快递袋,写上"地址、单号"(加 IP 头)
  v 贴上面单,写上"本小区 3 号楼"(加 MAC 头)
  v 交给快递员(物理传输)

到了分拣中心:
  v 撕掉面单(拆 MAC 头)—— 因为要重新决定下一站
  v 看快递袋上的地址(IP 头)—— 决定往哪发
  v 贴上新面单(加新 MAC 头)—— 下一跳

到了收件人:
  v 撕面单(拆 MAC)
  v 撕快递袋(拆 IP)
  v 拆信封(拆 TCP)
  v 拿到信(应用层数据)

关键:分拣中心(路由器)只拆到"快递袋"(IP 层),不会拆信封(TCP 层)。这是分层的精髓——每一层只关心自己那层的头。

核心机制 ​

一、封装:从上往下,逐层加头 ​

假设浏览器要发一个 HTTP 请求 GET /a:

应用层   GET /a HTTP/1.1  +  Host: x.com
           |
           |  加 TCP 头:源端口、目的端口、序号、窗口
           v
传输层   [TCP头][GET /a ...]
           |
           |  加 IP 头:源 IP、目的 IP、TTL
           v
网络层   [IP头][TCP头][GET /a ...]
           |
           |  加 MAC 头:源 MAC、目的 MAC、校验
           v
链路层   [MAC头][IP头][TCP头][GET /a ...][FCS]

每个头解决的问题:

层头里有什么解决什么
链路层源 MAC、目的 MAC这一跳交给谁
网络层源 IP、目的 IP、TTL最终送到哪、能活多久(防环)
传输层源端口、目的端口、序号、确认号、窗口交给哪个进程、保证不丢不乱

二、MTU 与 MSS:为什么要切 ​

MTU(Maximum Transmission Unit)= 链路层能承载的最大帧载荷,以太网默认 1500 字节
MSS(Maximum Segment Size)= TCP 段的最大数据长度 = MTU - IP头(20) - TCP头(20) = 1460

为什么要切:链路层一次传不了那么大的数据。你发 1MB 的数据,TCP 会切成约 700 个 MSS 大小的段。

切太大会怎样:如果 IP 包超过 MTU 且不允许分片,会被丢弃,返回 ICMP "需要分片"。这就是 PMTUD(路径 MTU 发现) 要解决的问题,也是某些网络"能 ping 通但打不开网页"的原因。

三、转发:每一跳发生了什么 ​

主机 A --> 路由器 1 --> 路由器 2 --> 主机 B

在主机 A:

  1. 查路由表:目的 IP 不在本网段 > 交给默认网关(路由器 1)。
  2. 查 ARP:网关 IP 对应的 MAC 是多少。
  3. 封装:目的 MAC = 路由器 1 的 MAC,目的 IP = 主机 B 的 IP。

在路由器 1:

  1. 拆链路层头(看目的 MAC 是自己,收下)。
  2. 看 IP 头里的目的 IP,TTL 减 1,查路由表决定下一跳。
  3. 重新封装:目的 MAC = 路由器 2 的 MAC,源 MAC = 路由器 1 出接口的 MAC,IP 头不变。

必记结论:

  • MAC 每跳都变,IP 端到端不变(NAT 场景例外)。
  • TTL 每跳减 1,减到 0 就丢弃并回 ICMP 超时——这是 traceroute 的原理。

四、分片与重组 ​

IP 层如果遇到超过 MTU 的包,可以分片(IPv4)。但分片很糟:

  • 任一分片丢失,整个包要重传。
  • 分片增加路由器负担。

所以现代做法是:IP 层不分片(设 DF 位),由 TCP 按 MSS 切好。IPv6 干脆取消了路由器分片。

五、端口:数据交给哪个进程 ​

一个 TCP 连接由四元组唯一标识:
  (源IP, 源端口, 目的IP, 目的端口)

所以:
  同一个客户端可以同时开很多连接访问同一个服务器 —— 源端口不同
  一个服务器端口(比如 80)可以同时服务成千上万个连接 —— 靠四元组区分

这解释了一个常见疑问:为什么服务端只监听一个 80 端口,却能处理上万并发?因为连接不是靠端口区分的,是靠四元组区分的。

六、完整时序 ​

① 浏览器 -> 本地 DNS   查询 www.example.com              【网络 05】
② 本地 DNS -> 浏览器   返回 IP 93.184.216.34
③ 浏览器 -> 服务器     SYN                                【网络 02】
④ 服务器 -> 浏览器     SYN+ACK
⑤ 浏览器 -> 服务器     ACK          => TCP 连接建立
⑥ 浏览器 -> 服务器     TLS 握手(若 HTTPS)               【网络 04】
⑦ 浏览器 -> 服务器     GET /index.html                    【网络 04】
⑧ 服务器 -> 浏览器     200 OK + HTML
⑨ 双向               数据分片、编号、滑动窗口            【网络 03】
⑩ 浏览器 -> 服务器     FIN                                【网络 02】
⑪ 服务器 -> 浏览器     ACK
⑫ 服务器 -> 浏览器     FIN
⑬ 浏览器 -> 服务器     ACK          => 连接关闭

为什么这么设计 ​

反事实 1:如果不分层,会怎样 ​

一个协议要同时管"找路 + 不丢包 + 数据格式 + 加密"。后果:

  • 换 WiFi 就要重写整个协议栈。
  • 想给 HTTP 加密(HTTPS),得改底层寻址逻辑。
  • 每个应用(邮件、网页、视频)都要自己实现可靠传输。

分层让每一层可以独立演进:HTTP/2 只改了应用层,TCP 一点没动;QUIC 把可靠传输搬到 UDP 上,只动了传输层。

反事实 2:如果路由器要拆到应用层,会怎样 ​

路由器要理解 HTTP、SMTP、FTP 每种协议的格式——不可能,而且每出一个新协议就要升级所有路由器。

所以路由器只拆到 IP 层:它只需要知道"目的 IP 是谁",不需要知道"里面装的是什么"。这就是"端到端原则":复杂的功能放在端上,网络中间尽量简单。

反事实 3:如果没有端口,会怎样 ​

一台机器上跑着浏览器、微信、数据库。数据到了,交给谁?

没有端口的话,只能靠"应用自己识别数据"——每个应用都要读所有收到的包,判断"这是不是我的"。既低效又不安全。

端口本质是给进程编了个号,让内核能直接分发。

面试怎么问 ​

Q:TCP/IP 四层(或 OSI 七层)分别是什么?各层有什么协议?

四层:应用层(HTTP/DNS/FTP)、传输层(TCP/UDP)、网络层(IP/ICMP/ARP 争议)、链路层(以太网/ARP)。 七层:物理、数据链路、网络、传输、会话、表示、应用。说完补一句"OSI 是教学模型,实际是 TCP/IP 四层",显得不背书。

Q:数据从应用层到物理层,经过了什么?

逐层封装,每层加头:TCP 头(端口、序号)> IP 头(IP、TTL)> MAC 头(MAC、FCS)。到对方逐层解封装,每层拆自己那个头,把剩下的往上交。

Q:路由器转发时,什么变了什么没变?

变了:源 MAC、目的 MAC(每跳重写)、TTL(每跳减 1)。 没变:源 IP、目的 IP(NAT 场景除外)、TCP 头(端口、序号全部不变)。 这是区分"懂不懂分层"的经典题。

Q:为什么服务端一个端口能处理上万连接?

因为连接由四元组标识(源IP、源端口、目的IP、目的端口),不是由端口标识。不同客户端的源 IP/端口不同,就是不同的连接。

追问链:

一次请求经过哪些层?
  > 每层加了什么头?(端口 / IP / MAC)
    > 路由器拆到哪一层?(只到 IP 层)
      > 为什么不多拆?(端到端原则,中间要简单)
        > MAC 每跳都变,IP 不变,为什么?(MAC 只管这一跳)
          > 那 NAT 呢?(NAT 会改 IP,所以破坏了端到端,是过渡方案)

和其他知识的连接 ​

自测 3 问 ​

Q1:路由器转发时,为什么要重写 MAC 头?

点开看答案

因为 MAC 地址只在同一个局域网(广播域)内有效。

主机 A 和主机 B 可能隔了 10 个路由器,A 根本不知道 B 的 MAC(也不需要知道)。A 只知道"下一跳是网关",所以把目的 MAC 写成网关的。

网关收到后,要发给下一个网关,就得把目的 MAC 改成下一个网关的 MAC。每一跳都是"当前节点 > 下一个节点"的关系,所以 MAC 每跳都要重写。

而 IP 是端到端的最终地址,全程不变(NAT 除外)。

Q2:为什么服务端 80 端口能同时处理上万连接?

点开看答案

因为端口不是连接的唯一标识,四元组才是:

(客户端IP, 客户端端口, 服务器IP, 服务器端口)

一万个客户端连过来,服务器 IP 和端口都是 1.2.3.4:80,但客户端 IP/端口各不相同,所以是 1 万个不同的连接。

内核的 socket 表按四元组查找,每个连接一个 socket 结构。"监听 80 端口"的那个 socket 只负责接受新连接(accept),接受后创建的新 socket 才承载数据。

Q3:TTL 是干什么的?为什么需要它?

点开看答案

TTL(Time To Live)是 IP 头里的一个计数器,每经过一个路由器减 1,减到 0 就丢弃并回一个 ICMP 超时。

存在理由:防止路由环路把网络打爆。如果路由表配错形成环,包会在两个路由器之间无限打转,每秒几百万个包会把链路彻底堵死。有了 TTL,最多转 64 跳就死掉。

副产品:traceroute 就是利用它——发 TTL=1 的包,第一个路由器回超时,就知道第一跳是谁;TTL=2 就知道第二跳,依次推出整条路径。

类比失效处 / 易错点 ​

  • "快递袋"类比会让人以为分拣中心要拆开看。实际路由器只看 IP 头,连 TCP 头都不看(除了 NAT 和防火墙)。
  • "每层加头"不是无限的。头本身有开销:TCP+IP 头 40 字节,如果数据只有 1 字节,开销率 97.6%。所以小包合并(Nagle 算法)是有意义的。
  • ARP 到底属于哪一层有争议。它工作在链路层和网络层之间,通常归为链路层,但它处理的是 IP 地址。
  • "OSI 七层"不要和"TCP/IP 四层"混着说。面试时先答四层(实际),再提七层(模型)。
  • IP 头不变,但 IP 包可能被分片。分片后每个分片有自己的 IP 头(部分字段复制),重组在目的主机完成。

✅ 验收清单 ​

  • 能画出封装/解封装图,标出每层加的头和头里的关键字段
  • 能说出路由器转发时"什么变、什么不变"(MAC 变、IP 不变、TTL 减 1)
  • 能解释为什么路由器只拆到 IP 层(端到端原则)
  • 能用四元组解释"一个 80 端口为什么能扛上万连接"
  • 能算出 MSS = MTU - 40,并说出为什么要切段
  • 能解释 TTL 的两个作用(防环 + traceroute 原理)
  • 合上书,用自己的话讲 3 分钟,中途不卡壳