不知道你是否曾经好奇你发出的一个网络请求,最终是怎么到达对端,并将你想要的信息返回给你的。本文将通过一个 HTTP 请求与响应,从一个比较宏观的角度来梳理下一个数据包在网络中的旅途,旨在帮助笔者和各位读者建立起对计算机网络模型一个比较全面的认知。

本文参考极客时间《网络架构实战课(谢友鹏)》,再根据笔者的知识面、按照个人理解,补充更多丰富具体的内容。

实战

好,那我们直接开始,我们先使用 curl 来发起一个 HTTP 请求,看看这过程中发生了什么:

1
curl -o /dev/null -v https://example.com

在笔者的 mac 机器上,这行命令的输出如下:

curl https//example.com 结果分析

当我们发起请求时,首先会对 example.com 进行域名解析,分别尝试解析到它的 IPv6IPv4

1
2
* IPv6: (none)
* IPv4: 23.215.0.138, 96.7.128.198, 23.192.228.80, 23.192.228.84, 23.215.0.136, 96.7.128.175

因为我们使用的是 https 协议,所以会尝试跟这些地址的 443 端口建立 TCP 连接,(如果是 https 则跟 80 端口),并进行 TLS 握手验证,如果成功了,则会建立 TCP 连接。

1
2
3
*   Trying 23.215.0.138:443...
...[TLS handshake]
* Connected to example.com (23.215.0.138) port 443

建立连接后,就开始发送 HTTP 请求,这里使用的是 HTTP2 协议。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
* using HTTP/2
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* [HTTP/2] [1] OPENED stream for https://example.com/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: example.com]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.10.1]
* [HTTP/2] [1] [accept: */*]
} [5 bytes data]
> GET / HTTP/2
> Host: example.com
> User-Agent: curl/8.10.1
> Accept: */*
>
* Request completely sent off

最后,服务器返回了 HTTP 200 OK 的响应。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [265 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [265 bytes data]
< HTTP/2 200
< content-type: text/html
< etag: "84238dfc8092e5d9c0dac8ef93371a07:1736799080.121134"
< last-modified: Mon, 13 Jan 2025 20:11:20 GMT
< cache-control: max-age=1374
< date: Sat, 01 Mar 2025 05:01:03 GMT
< alt-svc: h3=":443"; ma=93600,h3-29=":443"; ma=93600,quic=":443"; ma=93600; v="43"
< content-length: 1256
<
} [5 bytes data]
100 1256 100 1256 0 0 1172 0 0:00:01 0:00:01 --:--:-- 1172
* Connection #0 to host example.com left intact

要进一步了解网络数据包的细节,我们可以通过抓包工具进行分析。你可以使用 tcpdump 抓取与 example.com 的通信数据包。

运行如下命令:

1
sudo tcpdump host example.com -w example.com.pcap

然后再另外一个命令行窗口再次发送请求:

1
curl -o /dev/null -v https://example.com

回到 tcpdump 的窗口并结束监听,我们就会得到 example.com.pcap 的抓包文件,可以通过 Wireshark 软件打开该文件:

tcpdump 分析结果

网络分层

通过上述实验,我们可以清晰看到网络是分层的,主流的分层模型有 OSI 七层模型和 TCP/IP 四层模型,它们的对应关系及常见的协议如下图所示:

OSI-vs-TCP/IP

我们在 Wireshark 上方随便选择一个数据包,使用鼠标点击下方左侧的每一层,可以在右侧看到对应的层级数据。从链路层到应用层,每一层的数据都是对下一层的进一步封装。

数据包封装

在发送方,用户程序需要传输的数据会经过逐层封装。首先添加应用层的 HTTP Header,然后是传输层的 TCP Header,接着是网络层的 IP Header,最后在链路层添加以太网帧的帧头和帧尾,包括源 MAC 地址、目的 MAC 地址等链路层信息,最终形成网络中传输的完整数据包。

在接收方,数据包会按相反的顺序逐层解封装。接收设备从链路层开始解析数据,依次解读网络层、传输层和应用层的信息,最后将数据传递给接收方的应用程序。

如下图所示:

数据包封装 & 解析

我们在 Wireshark 中点开下面的每一层,可以看到如下信息,我在图标注了最重要的几个信息:网络数据包关键信息

网络之旅

经过上述实验,我们可以做个小总结:

通过上述实验,我们可以清晰理解数据包的传输过程:

  • HTTP 请求是网络通信的应用层内容,它需要通过各层网络协议的封装才能实现端到端传输。
  • 从发送方角度,数据传输遵循一个明确的逻辑顺序:首先将域名(example.com)解析为 IP 地址,然后基于该 IP 地址和目标端口(443)建立 TCP 连接,接着找到目标 IP 的 MAC 地址,最终由网卡将完整封装的数据包发送到网络中。
  • 从接收方角度,服务器处理数据包的过程是一个自下而上的解封装过程:数据链路层接收到的帧包含源 MAC 地址,网络层解析出 IPv4 地址和协议类型,传输层识别出 TCP 协议和源端口号,最终在应用层获取并处理 HTTP 请求数据。服务器根据这些信息构建响应,并按相反顺序封装返回给客户端。

这种分层处理机制确保了网络通信的灵活性和可靠性,每层只需关注自己的职责,共同完成端到端的数据传输任务。

好,那么这里就有 2 个最关键的问题:

  1. 如何通过域名获得 IP 地址?
  2. 如何通过 IP 地址获取 MAC 地址?

DNS 解析

DNS(Domain Name System,域名系统)是互联网的一项核心服务,它允许我们使用易记的域名(如 example.com)而不是数字 IP 地址(如 93.184.216.34)来访问网站。

当你在浏览器中输入一个域名时,DNS 解析按以下步骤进行:

  1. 浏览器缓存检查:浏览器首先检查自己的缓存,看是否已经存储了该域名对应的 IP 地址。

  2. 操作系统缓存检查:如果浏览器缓存中没有,系统会检查操作系统的 DNS 缓存(如 Windows 的 DNS Client 服务)。

  3. 路由器缓存检查:若系统缓存中也没有,请求会被发送到你的路由器,它也维护着一个 DNS 缓存。

  4. ISP DNS 服务器查询:如果以上缓存都未命中,请求会被发送到你的 ISP(互联网服务提供商)的 DNS 服务器。

  5. 递归查询:ISP 的 DNS 服务器会执行递归查询:

    • 首先查询根域名服务器(Root DNS Server)
    • 根服务器会引导到顶级域名服务器(TLD DNS Server,如 .com, .net, .org 等)
    • 顶级域名服务器会引导到权威域名服务器(Authoritative DNS Server)
    • 权威服务器会返回该域名的 IP 地址
  6. 结果返回与缓存:一旦获取到 IP 地址,它会被沿着查询路径返回,并在各个层级上缓存一段时间(由 TTL 值决定)。

你可以使用以下工具查询 DNS 信息:

  • nslookupnslookup example.com
  • digdig example.com
  • hosthost example.com

这些工具可以帮助你了解域名的解析过程和结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
➜  ~ host example.com
example.com has address 23.215.0.138
example.com has address 23.192.228.84
example.com has address 23.215.0.136
example.com has address 23.192.228.80
example.com has address 96.7.128.175
example.com has address 96.7.128.198
example.com has IPv6 address 2600:1408:ec00:36::1736:7f31
example.com has IPv6 address 2600:1406:3a00:21::173e:2e65
example.com has IPv6 address 2600:1406:3a00:21::173e:2e66
example.com has IPv6 address 2600:1406:bc00:53::b81e:94c8
example.com has IPv6 address 2600:1406:bc00:53::b81e:94ce
example.com has IPv6 address 2600:1408:ec00:36::1736:7f24
example.com mail is handled by 0 .

通过 DNS 解析将域名转换为 IP 地址后,网络通信的下一步就是确定如何将数据包发送到目标 IP 地址,这就需要用到 ARP 协议来获取目标设备的 MAC 地址。

穿越客户端局域网

当我们发送一个网络请求时,数据包如何找到离开家庭/办公网络的"出口"?

数据包首先需要解决的是"该往哪走"的问题:

  1. 问题:我需要直接联系目标设备还是找个"中介"?

    解决方案:子网判断

    • 设备会比较目标 IP 与自己的 IP 和子网掩码
    • 就像判断收件人是不是住在同一个小区
  2. 问题:如何找到同一网络中的设备?

    解决方案:ARP 协议

    • 类似于小区广播:"谁是 202 号房的?请告诉我你的门牌号!"
    • 目标设备回应自己的 MAC 地址(设备的"身份证号")
  3. 问题:目标在远方,如何离开本地网络?

    解决方案:默认网关

    • 就像不认识远方收件人的地址,先交给小区门卫(路由器)
    • 数据包头上标注最终目的地 IP,但先送到网关的 MAC 地址
  4. 问题:数据如何在本地网络中转发?

    解决方案:交换机的 MAC 地址表

    • 交换机就像小区内的快递员,记住了每家每户的门牌号
    • 它查表后将包裹精确送到对应的门口,不会打扰其他住户

简单来说,数据包在本地网络中的旅程就像是快递先确认收件人是否在同一小区,如果是,直接送达;如果不是,则交给小区出口的保安,由他负责进一步转发。

穿越公网

数据包离开了本地网络,如何在茫茫互联网中找到遥远的目标服务器?

数据包在互联网上的旅程就像一次跨国旅行:

  1. 问题:如何从私人区域进入公共世界?

    解决方案:NAT(网络地址转换)

    • 就像多人共用一个护照出国,本地设备共享一个公网 IP

    • 路由器会记住谁发了什么请求,回程时能送回正确的设备

  2. 问题:互联网如此庞大复杂,谁来管理这些网络?

    解决方案:自治系统(Autonomous System, AS)

    • AS 就像互联网世界的"国家"或"独立王国"

    • 每个 AS 由单一技术管理机构控制(如 ISP、大企业或教育机构)

    • 你的数据包首先进入你的 ISP 所在的 AS,然后可能穿越多个 AS

    • 每个 AS 有唯一的 AS 号(ASN),如 AS7018(AT&T) 或 AS8075(Microsoft)

  3. 问题:这些"网络王国"如何相互通信和合作?

    解决方案:BGP 协议(边界网关协议)

    • BGP 是 AS 之间的"外交语言",用于宣告路由信息

    • 它告诉其他 AS:"通过我可以到达这些网络"

    • 路由器根据 BGP 信息,决定数据包应该经过哪些 AS

  4. 问题:如何决定数据包在 AS 内部该走哪条路?

    解决方案:内部路由协议

    • AS 内部使用 OSPF 或 IS-IS 等协议来找到最佳路径

    • 路由器像城市中的交通指挥,根据"路况"决定下一个方向

  5. 问题:不同运营商之间如何连接?

    解决方案:互联网交换中心(IXP)

    • 就像不同航空公司在大型枢纽机场交换乘客

    • 数据包在 IXP 从一个 AS “转机”到另一个 AS

    • 这减少了路径长度,提高了传输效率

  6. 问题:我能知道我的数据经过了哪些地方吗?

    解决方案:路径追踪工具

    • traceroute/tracert 就像给数据包装上 GPS

    • 你可以看到数据包穿越的不同 AS 和路由器

互联网就像一个巨大的全球快递网络,你的数据包可能穿越多个国家、经过海底电缆,由不同的运营商接力传递,最终到达目的地的网络。

穿越服务端局域网

数据包到达目标所在网络后,如何找到并到达最终的服务器?

数据包抵达目的地网络,就像国际快递到达目标城市,还需要最后一段"本地配送":

  1. 问题:如何确保只有合法请求能进入网络?

    解决方案:防火墙和安全策略

    • 就像机场海关,检查入境者是否符合入境条件
    • 只有合法的数据包才能通过安全检查
  2. 问题:大型网站如何处理海量请求?

    解决方案:负载均衡

    • 像大型医院的分诊台,将病人分配到不同的医生处
    • 根据服务器负载、用户位置等因素智能分发请求
  3. 问题:如何在数据中心复杂环境中找到目标服务器?

    解决方案:内部路由与最后一跳 ARP

    • 数据中心内部有自己的"地图"和"道路系统"
    • 最后一个路由器会通过 ARP 找到服务器的具体位置
  4. 问题:现代云环境中,服务器可能是虚拟的,怎么处理?

    解决方案:虚拟网络

    • 物理服务器上可能运行多个虚拟机或容器
    • 虚拟交换机将数据包准确送达虚拟环境中的目标应用

这就像国际快递最后的“最后一公里”配送 - 从目的地城市的分拣中心,经过层层筛选,最终送到收件人手中。

总结

网络请求就像一封国际信件的旅程:

  1. 本地投递:从你家出发,判断收件人是否在同小区。如不在,交给小区出口的门卫(网关)。

  2. 国际运输:

    • 先经过你所在“国家”(你 ISP 的 AS)的海关(NAT)
    • 然后可能穿越多个“国家”(不同的 AS)
    • 各国海关(路由器)通过“国际条约”(BGP)决定包裹走向
    • 有时通过“国际中转站”(IXP)快速转运到其他“国家”
  3. 目的地配送:

    • 通过目的地“海关”(防火墙)入境检查

    • 经过“分拣中心”(负载均衡器)分配处理人员

    • 最终通过“本地快递员”(内部路由和交换)送达收件人手中

数据包就这样完成了客户端设备到服务器的全程旅行,然后服务器的响应再沿着类似的路径返回到客户端设备,完成整个请求-响应循环。

参考