键入 URL 到页面显示全过程
本文内容
前言
我们经常在浏览器的地址栏输入某个网站的网址,然后按下回车键,对应的页面就会呈现出来。那么你知道这中间都经历了什么吗?
先看一个简单的请求过程,过程中只涉及数据包在各个层级上的格式:
请求报文在经过各层时都会由不同的协议进行处理,下面就基于这些协议(和设备),来探究一个数据包的发送会经历些什么。
1. HTTP
首先,浏览器会 解析 URL,从中获取我们要请求的目标服务器和需要请求的资源文件,然后 构建 HTTP 请求。
HTTP 请求报文由三部分组成,分别是 请求行、请求头和请求体:
- 请求行:包含请求方法、请求资源文件的 URL 地址(不含域名)、使用的协议和版本号;
- 请求头:包含若干属性,格式为
属性名:属性值
,常见的属性包括接收的数据格式/编码/语言、目标服务器的域名、缓存控制、Cookie 等。 - 请求体:请求的内容。
请求报文的示例如下(详细的报文格式可以看 HTTP 入门):
2. DNS
浏览器解析 URL 生成 HTTP 请求报文后,报文中只有目标服务器的域名,所以接下来需要 对域名进行解析,得到 IP 地址。
而域名解析的工作,就是由 DNS 服务器 完成的,它保存了服务器域名与 IP 地址的对应关系。
2.1 域名的层级关系
DNS 中的域名使用点 .
来分割,比如 www.server.com
。越靠右 域名的 层级越高。
实际上域名最后还有个点,这个最后的点标识根域名,像这样 www.server.com.
。
所以上面的最高层级是根域 .
,下一层是顶级域名 .com
,再下一层是二级域名 server.com
。类似与下面这样的树形结构:
可以发现,通过根域的 DNS 服务器就可以把所有互联网中所有的 DNS 服务器串联起来了。
所以客户端只需要从任意一台 DNS 服务器开始向上寻找到根 DNS 服务器,再向下就可以寻找到任意一台 DNS 服务器。
2.2 域名解析流程
其实,客户端在查询一个域名对应的 IP 地址时,不一定非要先从上寻找到根 DNS 服务器,再往下寻找目标 DNS 服务器进行域名解析,因为域名对应 IP 地址的信息会有 缓存。
假设客户端要查询 www.baidu.com
的 IP 地址,查询过程如下:
在 浏览器缓存 中查询;
在 操作系统缓存(hosts 文件)中查询;
Linux 在
/etc/hosts
文件,Windows 在C:\Windows\System32\drivers\etc\hosts
文件。客户端向 本地 DNS 服务器 发起 DNS 解析请求。如果本地 DNS 服务器没有,则会向根 DNS 服务器发起请求,询问
www.baidu.com
的 IP 地址是什么;根 DNS 服务器 收到请求后,发现顶级域名是
.com
,则会告诉本地 DNS 服务器,你要查找的域名在.com
域名服务器上,返回.com
域名服务器的地址;本地 DNS 服务器收到
.com
域名服务器的地址后,就去问.com
服务器;.com
域名服务器收到请求后,就会返回baidu.com
域名服务器的地址;baidu.com
所属的域名服务器也称作权威 DNS 服务器,因为这个域名属于该服务器。本地 DNS 服务器收到后,就去
baidu.com
权威域名服务器 询问;权威域名服务器查询后,就会将对应的 IP 地址 返回给本地 DNS 服务器;
本地 DNS 服务器将最后的结果 返回给客户端。
整体的解析过程如下:
可以发现,在本地 DNS 服务器去查找时,其他域名服务器不会告诉它具体的结果,只会告诉它应该去哪儿找。
DNS 请求过程一般使用 UDP 协议,因为 DNS 请求过程就是一问一答,符合 UDP 的请求方式,而且开销也小(使用 TCP 只为了请求一条信息,太浪费了)。
3. TCP
HTTP 是基于 TCP 协议传输的,所以通信之前需要先 通过三次握手建立 TCP 连接。
HTTP 报文可能会非常大,为了合理控制传输效率,当数据包大小 超过 MSS(Maximum Segment Size,最大报文段长度)时,就需要将数据包 分块传输。这样即使传输过程有一个分块丢失了,也只需要重传这一个,大大提高了传输效率。
拆分完成后,在每块数据块的首部添加 TCP 头部,形成 TCP 报文,然后交给 IP 模块来发送数据。
TCP 报文的内容
TCP 头部会存放 源端口号,目的端口号 以及 TCP 相关的字段,TCP 报文的数据部分存放的就是 HTTP 报文。如下图所示:
4. IP
IP 模块会将数据块封装成网络包,IP 协议会将 TCP报文作为数据,再加上 IP 头部,封装成 IP 报文。如果 IP 报文大小 超过 MTU(Maximum Transmission Unit,最大传输单元),就会再次进行 分片。
IP 报文的主要内容
IP 头部会存放 源 IP 地址,目的 IP 地址 以及 IP 相关的字段,IP 报文的数据部分存放的就是 TCP 报文。如下图所示:
5. MAC
接下来,需要在 IP 报文头部加上 MAC 头部,生成 MAC 报文。MAC 头部含有源 MAC 地址和目的 MAC 地址。
发送方的 MAC 地址就在网卡里,读出来就行了,接收方的 MAC 地址需要使用 ARP 协议获取
(ARP 也有缓存,缓存中查不到就会以广播的形式询问某个 IP 地址的 MAC 地址)。
至此,一个完整的请求报文就生成完毕了,要开始在网络中传输了。
为什么需要 MAC 地址?
在 IP 头部中有目的地的 IP 地址,通过 IP 地址可以判断数据包要发往哪儿,但是 在以太网中,这个思路是行不通的。
以太网
以太网就是一种在「局域网」内,把附近的设备连接起来,使它们之间可以进行通讯的技术。
例如,电脑上的以太网接口、以太网交换机、路由器的以太网口,网线等,都是以太网的组成部分。
以太网在判断数据包的目的地时,和 IP 的方式不同,因此必须采用相匹配的方式才能在以太网中将数据包发往目的地,而这个方式,就是 MAC 地址。
MAC 头部是以太网使用的头部,它包含了接收方和发送方的 MAC 地址等信息,可以通过 ARP 协议 获取对方的 MAC 地址。
也就是说,需要使用 MAC 地址才能标识网络上的设备,才知道具体发往哪个地方。每台设备的 MAC 地址是唯一的,而 IP 地址不唯一(每个局域网内的 IP 地址才唯一)。
举个公司的例子,把 IP 地址比喻成工号,公司可以回收或者给别人用,或者在不不同的子公司也可以存在完全一样的工号。
有的公司员工离职后再回来,工号重新编。有的公司工号是永久编号,你离职了这个工号就空着,你回来了这个工号还是你的。所以完全看分配的策略,规则比较灵活。
而 Mac 就是一个设备一个编号号,规则不灵活,类似你的身份证号,你出生就有了,一生不变。
6. 网卡
网卡会在报文前面加上报头和起始帧分界符,使报文成为帧,能够在网络中传输。
最后网卡会将包转为电信号,通过网线发送出去。
7. 交换机
交换机工作在 MAC 层,它将网络包 原样 转发到目的地。
交换机会根据 MAC 地址表查找目的 MAC 地址,然后将报文发送到相应的端口。
举个例子,如果收到的包的目的 MAC 地址为 00-02-B3-1C-9C-F9
,则与图中表中的第 3 行匹配,根据端口列的信息,可知这个地址位于 3
号端口上,然后就可以通过交换电路将包发送到相应的端口了。
8. 路由器
网络包经过交换机后,会到达路由器,然后会将网络包转发到下一个路由器或者目标设备。
路由器的转发和交换机类似,也是通过查表判断包转发的目的地。
不过在具体的操作过程上,路由器和交换机是有区别的。
- 因为 路由器 是基于 IP 设计的,俗称 三层 网络设备,路由器的各个 端口 都具有 MAC 和 IP 地址;
- 而 交换机 是基于以太网设计的,俗称 二层 网络设备,交换机的 端口 不具有 MAC 和 IP 地址。
路由器的收、转、发:
收:路由器收到网络包后,会 检查目的 MAC 地址是否与自己端口的对应(路由器的端口具有 MAC 地址),是则接收;
转:接收完后,路由器就会 去掉 MAC 头部,然后 根据 IP 地址和路由表进行包的转发;
发:经过查表后,知道了目标的 IP 地址,然后使用 ARP 协议(路由器也有 ARP 缓存)查询对应的 MAC 地址,然后将网络包 再封装成 MAC 报文(添加 MAC 头部),最后通过端口发送出去。
发送出去的网络包会通过 交换机 到达下一个路由器。由于接收方 MAC 地址就是下一个路由器的地址,所以交换机会根据这一地址将包传输到下一个路由器。
接下来,下一个路由器会将包转发给再下一个路由器,经过层层转发之后,网络包就到达了最终的目的地。
在这个过程中,源 IP 和目标 IP 始终是不会变的,一直变化的是 MAC 地址,因为需要 MAC 地址在以太网内进行 两个设备 之间的包传输。
9. 服务端
数据包到了服务器后,由于发送时经过了层层封装,此时的数据包已经裹得很严实了,所以服务器会将这些头部信息依次扒开,最后取得真正的数据包。整体过程如下:
服务器在扒数据包的时候,会边扒边判断:
- 先扒开 MAC 头部,判断目的 MAC 地址是否和服务器的相对于;
- 接着扒开 IP 头部,判断 IP 地址是否对应,同时 IP 头部还有协议项,指示使用了 TCP 协议;
- 再扒开 TCP 头部,判断端口号属于哪个进程,同时还要看序列号是否是自己期望的,是则回复一个 ACK 应答信息;
服务器判断出该端口号属于 HTTP 进程,然后就把这个数据包发送给 HTTP 进程;
HTTP 进程发现是要要求一个页面,则会把这个页面也封装成一个 HTTP 响应报文。
这个响应报文也会经历之前的步骤,最终到达客户端,经过浏览器的渲染,最终页面就被显示了出来。
最后客户端要离开的时候,会向服务器发起 TCP 四次挥手,以断开连接。
一个小小的数据包,竟要经历如此坎坷才能到达目的地,不禁感叹我要经历些什么,才能到达我的目的地。。。