计算机网络 - 键入网址到页面显示发生了什么

617 阅读21分钟

想必不少⼩伙伴⾯试过程中,会遇到「当键⼊⽹址后,到⽹⻚显示,其间发⽣了什么」的⾯试题,接下来以下图较简单的⽹络拓扑模型作为例⼦,探究探究其间发⽣了什么?

image.png

1. 浏览器做的第⼀步⼯作是解析 URL

⾸先浏览器做的第⼀步⼯作就是要对 URL 进⾏解析,从⽽⽣成发送给 Web 服务器的请求信息。

image.png

image.png

image.png

所以图中的⻓⻓的 URL 实际上是请求服务器⾥的⽂件资源,当没有路径名时,就代表访问根⽬录下事先设置的默认⽂件,也就是 /index.html 或者 /default.html 这些⽂ 件,这样就不会发⽣混乱了。

2. ⽣产 HTTP 请求信息

对 URL 进⾏解析之后,浏览器确定了 Web 服务器和⽂件名,接下来就是根据这些信息来⽣成 HTTP 请求消息 了

image.png

⼀个孤单 HTTP 数据包表示:“我这么⼀个⼩⼩的数据包,没亲没友,直接发到浩瀚的⽹络,谁会知道我 呢?谁能载我⼀程呢?谁能保护我呢?我的⽬的地在哪呢?”

如果有对HTTP不熟悉的可以参考# 计算机网络-HTTP

3. DNS查询

通过浏览器解析 URL 并⽣成 HTTP 消息后,需要委托操作系统将消息发送给 Web 服务器.

但在发送之前,还有⼀项⼯作需要完成,那就是查询服务器域名对应的 IP 地址,因为委托操作系统发送消息时, 必须提供通信对象的 IP 地址

⽐如我们打电话的时候,必须要知道对⽅的电话号码,但由于电话号码难以记忆,所以通常我们会将对⽅电话号 + 姓名保存在通讯录⾥

有⼀种服务器就专⻔保存了 Web 服务器域名与 IP 的对应关系,它就是 DNS 服务器

3.1 域名的层级关系

DNS 中的域名都是⽤句点来分隔的,⽐如 www.server.com ,这⾥的句点代表了不同层次之间的界限,在域名中,越靠右的位置表示其层级越⾼。DNS是基于UDP协议

所以域名的层级关系类似⼀个树状结构:

  • 根 DNS 服务器
  • 顶级域 DNS 服务器(com)
  • 权威 DNS 服务器(server.com)

image.png

根域的 DNS 服务器信息保存在互联⽹中所有的 DNS 服务器中 ,因此客户端只要能够找到任意⼀台 DNS 服务器,就可以通过它找到根域 DNS 服务器,然后再⼀路顺藤摸⽠找到 位于下层的某台⽬标 DNS 服务器

3.2 域名解析的⼯作流程

  • 客户端⾸先会发出⼀个 DNS 请求,问 www.server.com 的 IP 是啥,并发给本地 DNS 服务器,如果缓存在该域名的IP 地址则返回。如果没有则本地 DNS 会去问它的根域名服务器 , 根域名服 务器是最⾼层次的,它不直接⽤于域名解析,但能指明⼀条道路。

  • 根 DNS 收到来⾃本地 DNS 的请求后,说“www.server.com 这个域名归 .com 区域管理”,我给你 .com 顶级域名服务器地址给你,你去问问它吧。”

  • 本地 DNS 收到顶级域名服务器的地址后,发起请求问“顶级域名服务器, 你能告诉我 www.server.com 的 IP 地址吗?” ,顶级域名服务器说:“我给你负责 www.server.com 区域的权威 DNS 服务器的地址,你去问它应该能问到”

  • 本地 DNS 于是转向问权威 DNS 服务器:“权威服务器,www.server.com对应的IP是啥呀?” , 权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。

  • 权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。

image.png

4. 指南帮手-协议栈

通过 DNS 获取到 IP 后,就可以把 HTTP 的传输⼯作交给操作系统中的协议栈。

协议栈的内部分为⼏个部分,分别承担不同的⼯作。上下关系是有⼀定的规则的,上⾯的部分会向下⾯的部分委托 ⼯作,下⾯的部分收到委托的⼯作并执⾏。

image.png

  • 应⽤程序(浏览器)通过调⽤ Socket 库,来委托协议栈⼯作。协议栈的上半部分有两块,分别是负责收发数据的 TCP 和 UDP 协议,它们两会接受应⽤层的委托执⾏收发数据的操作

  • 协议栈的下⾯⼀半是⽤ IP 协议控制⽹络包收发操作,在互联⽹上传数据时,数据会被切分成⼀块块的⽹络包,⽽ 将⽹络包发送给对⽅的操作就是由 IP 负责的。

此外 IP 中还包括 ICMP 协议和 ARP 协议:

1. ICMP ⽤于告知⽹络包传送过程中产⽣的错误以及各种控制信息
2. ARP ⽤于根据 IP 地址查询相应的以太⽹ MAC 地址
  • IP 下⾯的⽹卡驱动程序负责控制⽹卡硬件,⽽最下⾯的⽹卡则负责完成实际的收发操作,也就是对⽹线中的信号执 ⾏发送和接收操作。

如果对网络分层不清楚的可以参考# 计算机网络-网络分层

5. 可靠传输-TCP

HTTP 是基于 TCP 协议传输的,所以在这我们先了解下 TCP 协议。

我们先看看 TCP 报⽂头部的格式:

image.png

  • 源端⼝号和⽬标端⼝号是不可少的,如果没有这两个端⼝号,数据就不知道应该发给哪个应⽤。

  • 接下来有包的序号,这个是为了解决包乱序的问题。

  • 还有应该有的是确认号,⽬的是确认发出去对⽅是否有收到。如果没有收到就应该重新发送,直到送达,这个是为 了解决不丢包的问题。

  • 接下来就是⼀些状态位。例如 SYN 是发起⼀个连接, ACK 是回复, RST 是重新连接, FIN 是结束连接等。 TCP 是⾯向连接的,因⽽双⽅要维护连接的状态,这些带状态位的包的发送,会引起双⽅的状态变更。

  • 窗⼝⼤⼩。TCP 要做流量控制,通信双⽅各声明⼀个窗⼝(缓存⼤⼩),标识⾃⼰当前能够的 处理能⼒,别发送的太快,撑死我,也别发的太慢,饿死我。

  • 拥塞控制,对于真正的通路堵⻋不堵⻋,它⽆能为⼒,唯⼀能做的就是控制⾃ ⼰,也即控制发送的速度。不能改变世界,就改变⾃⼰嘛。

5.1 三次握⼿建⽴连接

所以三次握⼿⽬的是保证双⽅都有发送和接收的能⼒,本质上是双方相互交换序列号。

image.png

  1. ⼀开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端⼝,处于 LISTEN 状态。
  2. 然后客户端主动发起连接 SYN ,之后处于 SYN-SENT 状态。
  3. 服务端收到发起的连接,返回 SYN ,并且 ACK 客户端的 SYN ,之后处于 SYN-RCVD 状态。
  4. 客户端收到服务端发送的 SYN 和 ACK 之后,发送 ACK 的 ACK ,之后处于 ESTABLISHED 状态,因为它⼀ 发⼀收成功了。
  5. 服务端收到 ACK 的 ACK 之后,处于 ESTABLISHED 状态,因为它也⼀发⼀收了。

这里就不过多赘述TCP三次握手的细节,如果感兴趣的可参考# 计算机网络-TCP/UDP

5.2 如何查看 TCP 的连接状态?

TCP 的连接状态查看,在 Linux 可以通过 netstat -napt 命令查看

image.png

5.3 TCP报文生成

TCP 协议⾥⾯会有两个端⼝,⼀个是浏览器监听的端⼝(通常是随机⽣成的),⼀个是 Web 服务器监听的端⼝ (HTTP 默认端⼝号是 80 , HTTPS 默认端⼝号是 443 )。

在双⽅建⽴了连接后,TCP 报⽂中的数据部分就是存放 HTTP 头部 + 数据,组装好 TCP 报⽂之后,就需交给下⾯ 的⽹络层处理。

⾄此,⽹络包的报⽂如下图:

image.png

此时,遇上了 TCP 的 数据包激动表示:“太好了,碰到了可靠传输的 TCP 传输,它给我加上 TCP 头 部,我不再孤单了,安全感⼗⾜啊!有⼤佬可以保护我的可靠送达!但我应该往哪⾛呢?”

6. 远程定位-IP

TCP 模块在执⾏连接、收发、断开等各阶段操作时,都需要委托 IP 模块将数据封装成⽹络包发送给通信对象。

我们先看看 IP 报⽂头部的格式:

image.png

image.png

在 IP 协议⾥⾯需要有源地址 IP 和 ⽬标地址 IP:

  • 源地址IP,即是客户端输出的 IP 地址
  • ⽬标地址,即通过 DNS 域名解析得到的 Web 服务器 IP

因为 HTTP 是经过 TCP 传输的,所以在 IP 包头的协议号,要填写为 06 (⼗六进制),表示协议为 TCP。

假设客户端有多个⽹卡,就会有多个 IP 地址,那 IP 头部的源地址应该选择哪个 IP 呢?

当存在多个⽹卡时,在填写源地址 IP 时,就需要判断到底应该填写哪个地址。这个判断相当于在多块⽹卡中判断 应该使⽤哪个⼀块⽹卡来发送包。

这个时候就需要根据路由表规则,来判断哪⼀个⽹卡作为源地址 IP,在 Linux 操作系统,我们可以使⽤ route -n 命令查看当前系统的路由表。

image.png

6.1 IP报文生成

⾄此,⽹络包的报⽂如下图:

image.png

image.png

此时,加上了 IP 头部的数据包表示 :“有 IP ⼤佬给我指路了,感谢 IP 层给我加上了 IP 包头,让我有了 远程定位的能⼒!不会害怕在浩瀚的互联⽹迷茫了!可是⽬的地好远啊,我下⼀站应该去哪呢?”

7. 两点传输-MAC

⽣成了 IP 头部之后,接下来⽹络包还需要在 IP 头部的前⾯加上 MAC 头部。 MAC 头部是以太⽹使⽤的头部,它包含了接收⽅和发送⽅的 MAC 地址等信息。

image.png

在 MAC 包头⾥需要发送⽅ MAC 地址和接收⽅⽬标 MAC 地址,⽤于两点之间的传输。

⼀般在 TCP/IP 通信⾥,MAC 包头的协议类型只使⽤:

1. 0800 : IP 协议
2. 0806 : ARP 协议

MAC 发送⽅和接收⽅如何确认?

发送⽅的 MAC 地址获取就⽐较简单了,MAC 地址是在⽹卡⽣产时写⼊到 ROM ⾥的,只要将这个值读取出来写⼊ 到 MAC 头部就可以了。

接收⽅的 MAC 地址就有点复杂了,只要告诉以太⽹对⽅的 MAC 的地址,以太⽹就会帮我们把包发送过去,那么 很显然这⾥应该填写对⽅的 MAC 地址。

7.1 ARP寻找MAC地址

先得搞清楚应该把包发给谁,这个只要查⼀下路由表就知道了。在路由表中找到相匹配的条⽬,然后把包发给 Gateway 列中的 IP 地址就可以了。

既然知道要发给谁,按如何获取对⽅的 MAC 地址呢?

不知道对⽅ MAC 地址?不知道就喊呗。此时就需要 ARP 协议帮我们找到路由器的 MAC 地址.

image.png

  • ARP 协议会在以太⽹中以⼴播的形式,对以太⽹所有的设备喊出:“这个 IP 地址是谁的?请把你的 MAC 地址告诉 我”。

  • 然后就会有⼈回答:“这个 IP 地址是我的,我的 MAC 地址是 XXXX”。

  • 如果对⽅和⾃⼰处于同⼀个⼦⽹中,那么通过上⾯的操作就可以得到对⽅的 MAC 地址。然后,我们将这个 MAC 地址写⼊ MAC 头部,MAC 头部就完成了。

好像每次都要⼴播获取,这不是很麻烦吗?

在后续操作系统会把本次查询结果放到⼀块叫做 ARP 缓存的内存空间留着以后⽤,不过缓存的时间就⼏分钟, 也就是说在发包时:

1. 先查询 ARP 缓存,如果其中已经保存了对⽅的 MAC 地址,就不需要发送 ARP 查询,直接使⽤ ARP 缓存中的 地址。 
2. ⽽当 ARP 缓存中不存在对⽅ MAC 地址时,则发送 ARP ⼴播查询。

在 Linux 系统中,我们可以使⽤arp -a命令来查看 ARP 缓存的内容:

image.png

7.2 MAC报文生成

⾄此,⽹络包的报⽂如下图:

image.png

image.png

此时,加上了 MAC 头部的数据包万分感谢,说道 :“感谢 MAC ⼤佬,我知道我下⼀步要去哪了!我现 在有很多头部兄弟,相信我可以到达最终的⽬的地!”。 带着众多头部兄弟的数据包,终于准备要出⻔了。

8. 出口-网卡

⽹络包只是存放在内存中的⼀串⼆进制数字信息,没有办法直接发送给对⽅。因此,我们需要将数字信息转换为电信号,才能在⽹线上传输,也就是说,这才是真正的数据发送过程。负责执⾏这⼀操作的是⽹卡,要控制⽹卡还需要靠⽹卡驱动程序。

⽹卡驱动从 IP 模块获取到包之后,会将其复制到⽹卡内的缓存区中,接着会在其开头加上报头和起始帧分界符, 在末尾加上⽤于检测错误的帧校验序列

image.png

  1. 起始帧分界符是⼀个⽤来表示包起始位置的标记
  2. 末尾的 FCS (帧校验序列)⽤来检查包传输过程是否有损坏

最后⽹卡会将包转为电信号,通过⽹线发送出去:

唉,真是不容易,发⼀个包,真是历经千⾟万苦。致此,⼀个带有许多头部的数据终于踏上寻找⽬的地 的征途了!

9. 送别者-交换机

下⾯来看⼀下包是如何通过交换机的。交换机的设计是将⽹络包原样转发到⽬的地。交换机⼯作在 MAC 层,也称 为⼆层⽹络设备

9.1 交换机的包接收操作

⾸先,电信号到达⽹线接⼝,交换机⾥的模块进⾏接收,接下来交换机⾥的模块将电信号转换为数字信.

然后通过包末尾的 FCS 校验错误,如果没问题则放到缓冲区。这部分操作基本和计算机的⽹卡相同,但交换机的 ⼯作⽅式和⽹卡不同。

计算机的⽹卡本身具有 MAC 地址,并通过核对收到的包的接收⽅ MAC 地址判断是不是发给⾃⼰的,如果不是发 给⾃⼰的则丢弃;相对地,交换机的端⼝不核对接收⽅ MAC 地址,⽽是直接接收所有的包并存放到缓冲区中。因此和⽹卡不同,交换机的端⼝不具有 MAC 地址

将包存⼊缓冲区后,接下来需要查询⼀下这个包的接收⽅ MAC 地址是否已经在 MAC 地址表中有记录了.

交换机的 MAC 地址表主要包含两个信息:

  1. ⼀个是设备的 MAC 地址
  2. 另⼀个是该设备连接在交换机的哪个端⼝上

image.png

举个例⼦,如果收到的包的接收⽅ MAC 地址为 00-02-B3-1C-9C-F9 ,则与图中表中的第 3 ⾏匹配,根据端⼝列的信息,可知这个地址位于 3 号端⼝上,然后就可以通过交换电路将包发送到相应的端⼝了.

交换机根据 MAC 地址表查找 MAC 地址,然后将信号发送到相应的端⼝

  • 当 MAC 地址表找不到指定的 MAC 地址会怎么样?

这种情况下,交换机⽆法判断应该把包转发到哪个端⼝,只能将包转发到除了源端⼝之外的所有端⼝上,⽆论该设 备连接在哪个端⼝上都能收到这个包。

这样做不会产⽣什么问题,因为以太⽹的设计本来就是将包发送到整个⽹络的然后只有相应的接收者才接收包, ⽽其他设备则会忽略这个包

  • 这样做会发送多余的包,会不会造成⽹络拥塞呢?

其实完全不⽤过于担⼼,因为发送了包之后⽬标设备会作出响应,只要返回了响应包,交换机就可以将它的地址写 ⼊ MAC 地址表,下次也就不需要把包发到所有端⼝了。

10. 处境大门-路由器

⽹络包经过交换机之后,现在到达了路由器,并在此被转发到下⼀个路由器或⽬标设备。这⼀步转发的⼯作原理和交换机类似,也是通过查表判断包转发的⽬标。

路由器和交换机是有区别的:

1. 因为路由器是基于 IP 设计的,俗称三层⽹络设备,路由器的各个端⼝都具有 MAC 地址和 IP 地址;

2. ⽽交换机是基于以太⽹设计的,俗称⼆层⽹络设备,交换机的端⼝不具有 MAC 地址。

10.1 路由器基本原理

路由器的端⼝具有 MAC 地址,因此它就能够成为以太⽹的发送⽅和接收⽅;同时还具有 IP 地址,从这个意义上来 说,它和计算机的⽹卡是⼀样的。

当转发包时,⾸先路由器端⼝会接收发给⾃⼰的以太⽹包,然后路由表查询转发⽬标,再由相应的端⼝作为发送⽅ 将以太⽹包发送出去。

  • 路由器的包接收操作
1. ⾸先,电信号到达⽹线接⼝部分,路由器中的模块会将电信号转成数字信号,然后通过包末尾的 FCS 进⾏错误校验。 

2. 如果没问题则检查 MAC 头部中的接收⽅ MAC 地址,看看是不是发给⾃⼰的包,如果是就放到接收缓冲区中,否则就丢弃这个包。 

3. 总的来说,路由器的端⼝都具有 MAC 地址,只接收与⾃身地址匹配的包,遇到不匹配的包则直接丢弃。
  • 查询路由表确定输出端⼝
1. 完成包接收操作之后,路由器就会去掉包开头的 MAC 头部。 

2. MAC 头部的作⽤就是将包送达路由器,其中的接收⽅ MAC 地址就是路由器端⼝的 MAC 地址。因此,当包到达路 由器之后,MAC 头部的任务就完成了,于是 MAC 头部就会被丢弃。 

3. 接下来,路由器会根据 MAC 头部后⽅的 IP 头部中的内容进⾏包的转发操作。
  • 转发操作分为⼏个阶段 image.png

具体的⼯作流程根据上图,举个例⼦。

1. 假设地址为 10.10.1.101 的计算机要向地址为 192.168.1.100 的服务器发送⼀个包,这个包先到达图中的路由器。 

2. 判断转发⽬标的第⼀步,就是根据包的接收⽅ IP 地址查询路由表中的⽬标地址栏,以找到相匹配的记录。 

3. 路由匹配和前⾯讲的⼀样,每个条⽬的⼦⽹掩码和 192.168.1.100 IP 做 & 与运算后,得到的结果与对应条⽬的 ⽬标地址进⾏匹配,如果匹配就会作为候选转发⽬标,如果不匹配就继续与下个条⽬进⾏路由匹配。

4. 如第⼆条⽬的⼦⽹掩码 255.255.255.0 与 192.168.1.100 IP 做 & 与运算后,得到结果是 192.168.1.0 ,这与 第⼆条⽬的⽬标地址 192.168.1.0 匹配,该第⼆条⽬记录就会被作为转发⽬标。 

5. 实在找不到匹配路由时,就会选择默认路由,路由表中⼦⽹掩码为 0.0.0.0 的记录表示「默认路由」。
  • 路由器的发送操作
1. 如果⽹关是⼀个 IP 地址,则这个IP 地址就是我们要转发到的⽬标地址,还未抵达终点,还需继续需要路由器 转发。 

2. 如果⽹关为空,则 IP 头部中的接收⽅ IP 地址就是要转发到的⽬标地址,也是就终于找到 IP 包头⾥的⽬标地址 了,说明已抵达终点

知道对⽅的 IP 地址之后,接下来需要通过 ARP 协议根据 IP 地址查询 MAC 地址,并将查询的结果作为接收⽅ MAC 地址。

路由器也有 ARP 缓存,因此⾸先会在 ARP 缓存中查询,如果找不到则发送 ARP 查询请求。

接下来是发送⽅ MAC 地址字段,这⾥填写输出端⼝的 MAC 地址。还有⼀个以太类型字段,填写 0800 (⼗六进 制)表示 IP 协议。

⽹络包完成后,接下来会将其转换成电信号并通过端⼝发送出去。这⼀步的⼯作过程和计算机也是相同的。

发送出去的⽹络包会通过交换机到达下⼀个路由器。由于接收⽅ MAC 地址就是下⼀个路由器的地址,所以交换机 会根据这⼀地址将包传输到下⼀个路由器。

接下来,下⼀个路由器会将包转发给再下⼀个路由器,经过层层转发之后,⽹络包就到达了最终的⽬的地。

不知你发现了没有,在⽹络包传输的过程中,源 IP 和⽬标 IP 始终是不会变的,⼀直变化的是 MAC 地址,因为需 要 MAC 地址在以太⽹内进⾏两个设备之间的包传输.

数据包通过多个路由器道友的帮助,在⽹络世界途经了很多路程,最终抵达了⽬的地的城⻔!城⻔值守 的路由器,发现了这个⼩兄弟数据包原来是找城内的⼈,于是它就将数据包送进了城内,再经由城内的 交换机帮助下,最终转发到了⽬的地了。数据包感慨万千的说道:“多谢这⼀路上,各路⼤侠的相助!”

11. 相互扒皮-服务器 与 客户端

数据包抵达了服务器,服务器肯定⾼兴呀,正所谓有朋⾃远⽅来,不亦乐乎?

服务器⾼兴的不得了,于是开始扒数据包的⽪!就好像你收到快递,能不兴奋吗?

image.png

1. 数据包抵达服务器后,服务器会先扒开数据包的 MAC 头部,查看是否和服务器⾃⼰的 MAC 地址符合,符合就将 包收起来。 

2. 接着继续扒开数据包的 IP 头,发现 IP 地址符合,根据 IP 头中协议项,知道⾃⼰上层是 TCP 协议。 

3. 于是,扒开 TCP 的头,⾥⾯有序列号,需要看⼀看这个序列包是不是我想要的,如果是就放⼊缓存中然后返回⼀ 个 ACK,如果不是就丢弃。TCP头部⾥⾯还有端⼝号, HTTP 的服务器正在监听这个端⼝号。 

4. 于是,服务器⾃然就知道是 HTTP 进程想要这个包,于是就将包发给 HTTP 进程。 

5. 服务器的 HTTP 进程看到,原来这个请求是要访问⼀个⻚⾯,于是就把这个⽹⻚封装在 HTTP 响应报⽂⾥。

6. HTTP 响应报⽂也需要穿上 TCP、IP、MAC 头部,不过这次是源地址是服务器 IP 地址,⽬的地址是客户端 IP 地 址。 

7. 穿好头部⾐服后,从⽹卡出去,交由交换机转发到出城的路由器,路由器就把响应数据包发到了下⼀个路由器,就 这样跳啊跳。 

8. 最后跳到了客户端的城⻔把⼿的路由器,路由器扒开 IP 头部发现是要找城内的⼈,于是⼜把包发给了城内的交换 机,再由交换机转发到客户端。 

9. 客户端收到了服务器的响应数据包后,同样也⾮常的⾼兴,客户能拆快递了! 

10. 于是,客户端开始扒⽪,把收到的数据包的⽪扒剩 HTTP 响应报⽂后,交给浏览器去渲染⻚⾯,⼀份特别的数据包 快递,就这样显示出来了! 

11. 最后,客户端要离开了,向服务器发起了 TCP 四次挥⼿,⾄此双⽅的连接就断开了。

这⼀路上的经历,让我认识到了⽹络世界中各路⼤侠协作的重要性,是他们维护了⽹络世界的秩序,感谢他们! (我呸,你应该感谢众多计算机科学家!)