咨询干货

了解优化推广技术相关资讯

访问一个网页背后所经历了哪些过程

2019-05-15来自网络作者: 程序猿说

本文以访问一个实际的 HTTP 网站为例,讲述在访问一个网页背后所经历哪些过程。通过介绍各层协议是如何共同协作,最终完成网页数据传输,使得读者能够对该过程的理解更加清晰。本文以浏览器访问 URL 为例,其实在众多 APP 客户端工作的过程中,也是会访问各自服务器的 URL,从原理上来说和浏览器端的访问基本一致,可自行对应。

本文分析使用到的数据报文,我已经放在这个地方,可自行下载,对应着后续的讲述更加容易的理解整个分析过程。

本文以央视网这样一个 HTTP 网站为例来进行讲述。如果访问像这样一个常见的域名,由于为百度已经采用了全站加密的技术,这样的话会出现一些重定向, 同时 ssl 层还有一个建立连接的过程,对于网络协议还不是那么熟悉的同学来说可能会显得较为复杂。因此这里面使用一个没有重定向,基于 HTTP1.1 协议传输的网站会使问题的分析变的更加容易理解,同时目前国内的大多数网站还停留在 HTTP1.1 传输阶段,分析 HTTP1.1 传输也能够兼顾大多数的场景。虽然一些大的互联网企业都是积极的拥抱新技术,采用了 HTTPS,但是也可以看到,政府网站,学校网站,公司网站依然基于 HTTP1.1 传输居多。

在分析 HTTP1.1 传输的基础上再去尝试分析重定向以及 HTTPS,甚至已经开始应用的 HTTP2 等网站就变得很容易。需要说明的是本文只分析协议层次的访问流程,也就是以对主页 URL 的访问为例。至于主页上的脚本,图片等资源的加载请求的 URL 跟主页的请求在协议角度原理一致,不在赘述。

本文的分析主要分为三个层次:

  1. 站在各个协议层次来看协议间是如何对等传输的。
  2. 站在数据发送者角度自顶向下的分析,分析各层协议字段如何获取。
  3. 站在数据接受者的角度自底向上的分析,分析各层协议之间的联系。

一、对等传输

TCP/IP 模型如图 1:

访问一个网址会经历哪些流程


图 1

可以看到 TCP/IP 模型的协议栈包含四层,对等传输表达的就是如图 1 虚线所示,应用层之间互相通信,传输层之间互相交换数据,同理网络层和物理层。这里面以 HTTP 这个常见的应用层协议为例说明对等传输。

在浏览器中输入 http://www.cctv.com 这样一个网址,同时通过 Wireshark 工具抓取传输过程中的数据。使用 http.host contains "cctv" 过滤排除无用的数据包,可以看到有诸多的 http 请求和响应。如前所述,只考虑主页 URL 的请求,并选择第一条进行 follow,如图 2:

访问一个网址会经历哪些流程


图 2

这时候你发现访问 www.cctv.com 应用层使用了 HTTP 协议进行传输,为什么呢?因为浏览器地址栏这时候地址变成了 http://www.cctv.com/,也就是浏览器在访问 www.cctv.com 时候,会添加 http:// 这样一个协议头,默认了其传输协议为 HTTP。但是访问 gitchat 却是 https://gitbook.cn/ 这个样子的,前面也提到了会有 http://gitbook.cn/ 重定向到 https://gitbook.cn/ 的过程,为了问题的简化,本文不过多的讨论。如果你和服务器之间想通过 ftp 协议进行传输,那么在浏览器访地址栏输入的时候就要带上具体协议了,例如 ftp://image.cctv.com 这种形式,因为 image.cctv.com 会被默认为 http://image.cctv.com,ftp 协议是没有重定向的功能的。

从 HTTP 这个应用层来说,通信过程是这样的。

  1. 客户端发起一个 HTTP GET 请求。
  2. 服务器给出一个 HTTP/1.1 220 OK 的响应,同时传输具体的网页数据。整体来看,HTTP 协议过程非常的简单,就是请求和响应的过程。不仅 HTTP 如此,大多数的通信协议都是请求和响应的过程。

当然 HTTP 协议复杂程度远不止上述请求和响应那么简单。例如 HTTP 所规定的方法就还包括 POST,PUT,DELETE,CONNECT,OPTIONS,HEAD,TRACE 这几种,涵盖了数据的增删改查等方面。HTTP 的响应也还包括 1xx,2xx,3xx,4xx,5xx 等多种响应方式,分别表示不同的应答,例如信息类应答,成功的应答,重定向,客户端错误应答,服务器错误应答等等。

除了请求方法和响应码之外,还有丰富的 HTTP 头域,例如在请求阶段 Host 表示请求域名,Connection 表示长连接,User-Agent 表示客户端名称,Referer 表示请求来源,Aceept-Encoding 表示可接受传输的压缩编码方式等常见的请求头域。在响应阶段,可以看到 Expires 表示内容过期时间,Server 表示服务器名称,Content-Encoding 表示传输的压缩编码方式等常见的响应头域。

总体上看,可以理解为 HTTP 层是基于请求和应答(请求应答最终是协商服务器绝对路径,因此也可以认为是基于服务器绝对地址)所建立的虚拟链接。头域字段更多的是为了协商传输内容服务的。有了这样一个虚拟连接之后,自然而然的,数据就在 HTTP 层次对等的传输起来。如图 3:

访问一个网址会经历哪些流程


图 3

可以看到,我们忽略了所有的下层,认为 HTTP 层存在一条虚拟链接。同理可以认为 TCP 层是基于端口所建立的链接,当然关于 TCP 层的对等传输通常指的是 TCP 的三次握手,如图 4:

访问一个网址会经历哪些流程


图 4

TCP 的三次握手具体过程是:

  1. 客户端发起 TCP 连接(SYN)
  2. 服务器同意,并响应(SYN,ACK)
  3. 客户端也准备就绪,开始发数据(ACK)。

在一条流的结束时候,有四次挥手断开相应的 TCP 连接,如图 5:

访问一个网址会经历哪些流程


图 5

同样的 IP 层是基于 IP 地址所建立的链接,MAC 是基于 MAC 地址多建立的链接。当然显而易见的是,这些链接并不唯一。但是协议栈中各层析协议组合起来构成的链接在某个时刻就是唯一的一条链接,因此可以看到在复杂的网络中数据为什么非常有秩序的从一个终端流向另一个终端,正是这一条条唯一的链接所决定,不会跑偏。同时也可以看到协议中非常重要的一个要素就是地址,无论是 MAC 地址,IP 地址,端口,URL 都是一种地址,而地址就是通信的目的地。基于地址的链接就构成了协议层次的对等传输。

二、自顶向下

这个时候你可能会有疑问,在 TCP 对等传输中,端口从何而来,同样的 IP 和 MAC 地址从何而来。因为我们发现 HTTP 下层的 TCP 端口,IP 的地址这个时候都是已知的,如图 2 中所示。端口的获取过程很简单,系统自带 TCP 协议栈随机选择了一个客户端的端口,当然通常情况下客户端的端口都在默认在 30000 以上。同时由于传输协议是 HTTP 协议,因此端口为 80。因为 1-1024 这样一个保留端口是由 IANA 规定分配给指定的协议的,80 号端口就分配给了 HTTP 协议,后面的 53 号端口分配给了 DNS 是同样的道理,这是一个通用的标准,大多数的使用共有协议的服务都会遵守。如果想了解关于更多的常见端口信息,可以参见我写的文章,这里。客户端的 IP 就是本机 IP,服务器的 IP 地址的获取过程通过 DNS 来完成。

DNS 是域名解析协议,就是将域名转换为对应的 IP 地址,因为只有通过 IP 地址才能找到对应的主机所在。那么为什么不直接在浏览器里面输入 IP 地址的,这当然是可以的,但是由于 IP 地址没有域名方便于记忆,通常输入的都是域名,因此中间多了这一道过程,计算机设计的目的还是要方便于人。

使用 dns.qry.name == "www.cctv.com" 过滤得到 http://www.cctv.com/ 对应的 DNS 请求,如图 6:

访问一个网址会经历哪些流程


图 6

可以看到 DNS 使用的是 UDP 协议,源端口是本机分配的端口,由系统的 UDP 协议栈进行分配,而目的端口是 53,前面也提到了。因此协议栈在发送 DNS 协议的时候,将目的端口赋值为 53,长度则是由 DNS 长度来决定。

同样的 IP 层的目的地址从何而来?其实该地址是本机所配置的 dns 地址,如图 7:

访问一个网址会经历哪些流程


图 7

由于本机使用的是 DHCP 服务且使用的是电信的宽带,因此自动获取的最近的一个电信的 DNS,因此这里的目的地址就是电信的 DNS。当然如果你手动配置了 DNS,这时候的目的 IP 就是你所配置的目标 DNS,例如 114.114.114.114,以及 8.8.8.8 这些较为知名的 DNS 服务器,可以亲自手动设置下,抓包验证。

有了 IP 层的地址,那么以太网层的信息如何获取呢?首先上层是 Ipv4 协议,因此 type 字段就是确定的值,源地址就是本机的 MAC 地址,按照通常的思路,你可能理所当然的认为目的 MAC 应该是目的 IP 所对应的 MAC 地址,但是事实上并非如此。由于目的 IP 和源 IP 并不是处在同一个网段之中,通过 IP 地址和子网掩码与的结果并不相同得知。同时 MAC 层的通信规定的是局域网范围内的通信过程,对于不在同一个局域网内的主机来说,首先应该把数据包交给网关设备,由网关设备进行转发。

由于本机配置的网关为 192.168.0.1,图 7 所示,因此可以断定这里面配置的 MAC 为网关的 MAC 地址。因此在完成这个报文发送之前应该还有一个过程,获取网关的 MAC 地址,根据网关的 IP 地址获取网关的 MAC 过程就是 ARP 的过程。

介绍一下 ARP 的主要原理,如下:

  1. 先在 ARP 缓存中查看是否存在目的主机的的 IP 地址,windows 上可以通过在命令行输入 arp -a 查看。如果有,就把这个硬件地址写入相应的 MAC 层中。
  2. 如果没有目的 IP 地址,将在 ARP 帧中的目的 MAC 部分写全 F 形式表示广播该数据,因此网段内所有的主机或设备都能够接收到该数据帧。除了目的主机外,所有接收到该 ARP 请求帧的主机和设备都会丢弃该 ARP 请求帧。
  3. 目的主机收到请求后构造并发送 ARP 应答帧。
  4. 主机收到 ARP 响应后,将目的主机的物理地址作为一条新记录加入到 ARP 高速缓存表。

通过 ARP 过滤器进行过滤,如图 8

访问一个网址会经历哪些流程


图 8

由于本机的 ARP 缓存中有网关的记录,因此不用发送相应的广播包,但是发现 ARP 请求中填写了目的的 MAC 地址和 IP 地址,并且目的也给予了响应。这有可能是 ARP 具体实现过程中的刷新 ARP 缓存的一种优化策略,因为广播包毕竟会造成网络拥堵。

至此我们已经分析到了四层模型中的链路层,最底层了。在获取网关的 MAC 之后,会把该值填入 DNS 那条流中对应的以太网层中,图 6 中。网关在收到 DNS 报文之后,会使用路由选择协议,根据目的 IP 地址,将该数据包转发到下一跳网关路由器上,从而不断的在一个个小的局域网内部转发,最终达到目标 IP 所在的局域网,然后送达目标 IP 服务器。这个过程和快递的投送是类似的,快递的投送有没有借鉴该过程就不得而知了。

在 DNS 服务器收到相应的请求之后,就将对应的响应报文返回给客户端,如上图 6,数据不断通过路由选择协议在一个个局域网之间流动。客户在收到响应报文后,将报文交由协议栈中不同的层进行解封装处理,最终获取域名对对应的 IP 地址。

当然上述是基于 DNS 服务器中具有域名和 IP 的对应关系,则会返回对应的 IP 地址。如果域名服务器中没有,会作何处理。因为域名服务器的行为,本地是无法观测的,因此对于 DNS 原理作以下介绍。DNS 分为如下几步:

  1. 客户端查看本地缓存表,如果本地缓存表中存在域名和 IP 的对应关系,则可以获取相应的 IP 地址,在 windows 上的查看命令是 ipconfig /displaydns。当然有的浏览器也会缓存 IP 和域名的映射表,以加快连接的建立过程。但是各个浏览器的实现并不一致,这里不再讨论。
  2. 如果不存在,向 DNS 服务器发送 DNS 请求报文,来获取相应的 IP 地址。你可能会问 DNS 服务器在哪里?上面已经介绍过了,可以查看本机 DNS 服务器的配置情况。
  3. 同样的道理 DNS 服务器也可能没有相应的域名和 IP 的映射表,这个时候由 DNS 服务器(而不是客户端)会像根域名服务器发起请求 (全球 13 台,主要控制在美国手中) 询问,如果没有,根域名给出的是顶级域名服务器的 IP,例如通知你去询问 com 域服务器,com 域服务器上存在了所有 com 相关定义域名的一些记录。当然如果访问的是 mail.cctv.com 这样一个域名,com 域名服务器有可能会通知继续去询问 cctv 这样一个域名服务器等等,这是一个不断迭代的过程,由 DNS 服务器来完成。最终 DNS 服务器给出相应的 IP 地址,或者是报错。

至此获取访问 www.cctv.com 主页的那条流中 IP 地址,图 2 所示,主要是通过 DNS。在分析的过程中顺便分析了 DNS 流中 MAC 地址的获取方法以及数据如何在网络中不断的流动。有了前面 DNS 传输的例子,同样的关于该 HTTP 流中自顶向下的封装和 DNS 是一样的。

三、自底向上

客户端发送报文的时候,数据在协议栈中的流动是打上每层协议的协议头。客户在收到响应报文后,是如何获取最终的网页数据的呢?报文自底向上交,由协议栈中不同的层进行解封装处理,MAC 层处理前 14 个字节,IP 层,TCP 层以及 HTTP 层根据该层头部长度处理对应的字节数。这是一个自底向上解码的过程。在去掉所有协议头之后,剩下的数据部分就是网页数据。当然整个的网页数据是在将每一个包的网页数据按照顺序进行组合后形成的,如图 9:

访问一个网址会经历哪些流程


图 9

可以看到该网页由 42 个报文组成,报之间的顺序在 TCP 层已经通过 Sequence Number 定义了,Sequence Number 表示的就是数据相对于开始的偏移,因此不用担心乱序问题。既然数据在收到之后,是通过剥离协议头,按照 TCP 的 Sequence Number 交给客户端(也就是浏览器)时候,那么自然是可以根据报文数据来还原原始网页数据的,原理已经介绍过了。当然相应的还原方法有多种,我在上一篇 chat 中基于 Wireshark 插件介绍了一种简单实用的方法,感兴趣的可以参考之,见这里。

上述其实反映的是各层协议之间是存在一定联系,就是应用层数据顺序是由 TCP 传输层来决定的。当然 MAC 层有表示 IP 层协议的字段,以及 IP 层也有表示传输层协议字段也是各层联系的一个体现。

我们接下来以一个更为明显的例子加以说明。还记得在学习 TCP/IP 协议的时候,TCP 有 6 个标志位,像 ACK,FIN,SYN 都是喜闻乐见的标志位。但是 PUSH 这个标志位表示的是什么含义呢?在什么时候用呢?PUSH 标志位所表达的是发送方通知接收方应该尽快的将这个报文段交给应用层。传输层及以下的数据往往是由系统所带的协议栈进行处理的,客户端在收到一个个报文之后,经由协议栈解封装之后会立马把数据交给应用层去处理吗?如果说在收到报文之后立马就交给上层,这时候应用层由于数据不全,可能也不会进行处理。而且每来一个报文就交一次,效率很低。因此传输层一般会是隔几个报文,统一上交数据。什么时候上交数据呢,就是在发送方将 PUSH 标志位置 1 的时候。那么什么时候标志位会置 1 呢,通常是发送端觉得传输的数据应用层可以进行处理了的时候,如图 10 所示:

访问一个网址会经历哪些流程


图 10

由于通常网络较好的时候,数据会以满包状态进行传输,当然这里面是 1494 个字节,当一段数据传输完毕就会出现包长度下降,这时候 PUSH 就置 1,提示传输层尽快刷新数据交由应用层处理。其实一个更为明显的例子是 ssl 握手阶段,在服务器将证书传输完毕之后,是需要应用层赶紧处理,进行证书链的验证,因此会设置 PUSH 字段来告知传输层尽快上交数据,如图 11:

访问一个网址会经历哪些流程


图 11

可以找一个 ssl 报文观察,证书传输完毕时候,是否 PUSH 字段设置了。相信通过上述的分析,你不仅对于 PUSH 字段的实际应用有所理解,也对各层协议之间的联系印象深刻。

总结上述过程,对等传输就是 HTTP、TCP、IP、MAC 层分别建立链接。自顶向下就是分别打上各层的协议头,各层的地址等信息如何获取,又涉及到其他协议类似的过程。自底向上就是不断解封装过程,包括 MAC 层解封装,IP 层解封装,TCP 层解封装,HTTP 层解封装。当然各层协议之间不是独立的,存在一定的耦合,比如 PUSH 的作用等等。基于上述的一个分析,相信对于协议的分层机制,以及数据传输背后协议的工作流程就能够彻底的明白了。

声明:本站发布的内容以原创、转载、分享网络内容为主,如有侵权,请联系电话:021-51697771-8029,邮箱:mj@cndns.com,我们将会在第一时间删除。文章观点不代表本站立场,如需处理请联系我们。