HTTP网页从请求到响应过程详解

引言

本文针对于《计算机网络》课程内容的总结和扩展,主要是讲解浏览器从键入URL网址后,到网页显示,其间的过程。

首先,浏览器的第一步工作就是对 URL 进行解析,然后给向Web 服务器发送请求。我们先看下一条URL代表什么:
HTTP网页从请求到响应过程详解_第1张图片
举个例子:

https://www.jb51.net/article/223007.htm

其中 “www.jb51.net” 表示这台服务器,后面的 /article/223007.htm 表示我们请求的文件路径。但是这个路径是相对路径,是以web服务器根目录为起始目录的。如图:
HTTP网页从请求到响应过程详解_第2张图片
所以一个 URL 实际上对应Web服务器里的一个文件资源。如果没有输入路径名,例如只输入 “https://www.jb51.net” ,表示访问事先设置的默认文件,常见的有 /index.html 、 /default.html 等等。

对 URL 进行解析后,浏览器确定了 Web 服务器和文件名,接下来就是根据这些信息来构造 HTTP 请求报文。HTTP消息格式如图:
HTTP网页从请求到响应过程详解_第3张图片

域名解析过程

浏览器解析 URL 并生成 HTTP 数据结构后,在发给服务器之前,还需要查询域名对应的 IP 地址,因为操作系统发送消息时,必须提供通信对象的 IP 地址。

DNS 服务器就是专门保存 域名与 IP 的对应关系,负责解析域名的服务器 。注意:很多教材都说IP地址不方便记忆,所以才有了域名。其实域名不仅仅是方便记忆,他还有更重要的作用,比如用域名就可以实现一台服务器同时搭建多个网站而共用一个IP。

域名是用句点来分隔的,比如 www.server.com,这里的句点代表了不同层级的划分。在域名中,越靠右的位置表示其层级越高。

可能因为域名是外国人定义的,所以思维和中国人相反。比如表示一个地点,外国喜欢按照从小到大的顺序说(如 XX 街道 XX 区 XX 市 XX 省),而中国喜欢按从大到小的顺序(如 XX 省 XX 市 XX 区 XX 街道)。

最右边的是顶级域名,例如上面的 “.com” 。再下面是二级域名 server.com。所以域名的层级关系是一个树状结构(域名和域名服务器是两个概念):

  • 根 DNS 服务器
  • 顶级域 DNS 服务器(com)
  • 权威 DNS 服务器(server.com)
    HTTP网页从请求到响应过程详解_第4张图片

所有的 DNS 服务器都有根域DNS 服务器的信息。这样一来,任何 DNS 服务器都可以找到根域 DNS 。因此,客户端只要能够找到任意一台 DNS 服务器,就可以通过它找到根域 DNS 服务器,然后再一步步找到位于下层的某台目标 DNS 服务器。

域名解析过程:

  1. 首先查找电脑上的DNS缓存,如果有则解析完毕。否则进入第2步;
  2. 客户端向本地DNS服务器(可以在网络属性看到,一般是路由器自动设置,也可也手动设置)发送一个DNS请求,询问 www.jd.com的IP地址。本地DNS收到后,如果缓存里有,则直接返回对应的IP地址。否则第3步;
  3. 本地DNS向根DNS发送请求,询问 www.jd.com 的IP地址。根DNS收到后,发现是.com结尾的,便返回.com顶级DNS的地址给本地DNS。本地DNS收到后,向.com顶级DNS发起请求,询问www.jd.com的地址。顶级DNS返回负责jd.com域名的权威DNS地址。本地DNS于是向权威DNS请求,权威DNS查询后返回对应的IP地址。
  4. 本地DNS收到后,把结果返回给客户端,再缓存起来。

我们再看下解析过程图解:
HTTP网页从请求到响应过程详解_第5张图片

TCP/IP协议栈

经过上述步骤 获取到 IP 后, HTTP 的传输工作就交给系统中的协议栈了。协议栈的内部分为几个部分,分别承担不同的工作。上下关系是有一定的规则的,上面的部分会向下面的部分委托工作,下面的部分收到委托的工作并执行。如图:
HTTP网页从请求到响应过程详解_第6张图片

应用程序(浏览器)通过调用 Socket 库,来委托协议栈工作。协议栈的上半部分有两块,分别是负责收发数据的 TCP 和 UDP 协议,它们会接受应用层的委托执行收发数据的操作。协议栈的下面一半是用 IP 协议控制网络包收发操作,在互联网上传数据时,数据被划分为一个个的网络包,而将网络包发送给对方的操作就是由 IP 层负责的。

此外 IP 中还包括 ICMP 协议和 ARP 协议。ICMP 用于告知网络包传送过程中产生的错误以及各种控制信息。ARP 用于根据 IP 地址查询相应设备的 MAC 地址。IP 下面的网卡驱动程序负责控制网卡硬件,而最下面的网卡则负责完成实际的收发操作,也就是发送和接收比特流。

HTTP 是基于 TCP 协议传输的,所以先讲下 TCP 协议。我们先看 TCP 报文头部的格式:
HTTP网页从请求到响应过程详解_第7张图片
其中,源端口号和目标端口号是不可少的,这个端口号是区分应用程序的,如果没有,系统就不知道要传给哪个应用。包的序号是为了解决包先后到达的乱序问题。

确认号,目的是确认发出去对方是否有收到。如果没有收到就重新发送,直到送达,是为了解决丢包的问题。还有一些状态位。例如 SYN 表示发起一个连接,ACK 表示回复确认,RST 是重新连接,FIN 是结束连接。TCP 是面向连接的,因而双方要维护连接的状态,这些状态位就是调整连接状态的。

窗口大小,因为TCP 要做流量控制,所以通信双方需要各声明一个窗口(缓存大小),这个窗口表示本机当前的数据处理能力,控制对方发包的快慢。除了流量控制,TCP还会做拥塞控制,对于真正的网络拥堵,它无能为力,它只能控制自己这个连接,控制发送的速度。

在 HTTP 传输数据之前,通信双方要建立TCP连接,建立过程俗称“三次握手”。这个所谓的“连接”,只是计算机里维护的一个状态值,并不是真的在网络上有一条连接。

  1. 客户端处于 CLOSED 状态。服务端一直在监听某个端口,处于 LISTEN 状态。
  2. 客户端主动发起连接 SYN,之后处于 SYN-SENT 状态。
  3. 服务端收到连接请求,返回 SYN,并且 ACK 客户端的 SYN,之后处于 SYN-RCVD 状态。
  4. 客户端收到服务端发送的 SYN 和 ACK 之后,发送 ACK 的 ACK,之后处于 ESTABLISHED 状态。
  5. 服务端收到 ACK 的 ACK 之后,处于 ESTABLISHED 状态,自此,双方都经历了一发一收。

三次握手目的是保证双方都有发送和接收的能力。 Linux 系统可以通过命令 netstat -napt 查看本机有哪些连接以及状态。

如果 HTTP 请求消息比较长,超过了 MSS 的长度,这时 TCP 就需要把 HTTP 的数据进行划分。MTU 与 MSS 区别如图:HTTP网页从请求到响应过程详解_第8张图片

MTU是一个网络包的最大长度,我国一般定为 1500 字节。MSS是除去 IP 和 TCP 头部后,一个网络包所能容纳的 TCP 数据的最大长度,那必然是小于1500字节的。数据会按照 MSS 的长度进行划分,划分出来的每一块数据都会被放进单独的网络包中。即每个被拆分的数据都要加上 TCP 头信息,然后再交给 IP 层处理。如图:
HTTP网页从请求到响应过程详解_第9张图片
前面我们讲了,TCP 协议头部有两个端口,一个是浏览器监听的端口(通常是随机生成),一个是 Web 服务器监听的端口(HTTP 默认是 80, HTTPS 默认是 443)。在双方建立了连接后,TCP 报文中的数据部分就是存放 HTTP 头部 + 数据,组装好 TCP 报文之后,就交给下面的网络层处理。HTTP的数据经过TCP处理后,报文大致如下:
HTTP网页从请求到响应过程详解_第10张图片
TCP 模块在执行连接、收发、断开等各阶段操作时,都需要依托 IP 模块将数据封装成网络包发送给通信对象。我们再看 IP 报文头部的格式:
HTTP网页从请求到响应过程详解_第11张图片
IP 报头需要有源 IP 和 目标 IP,前者是客户端的 IP 地址,后者是 服务器 IP地址。因为 HTTP 是基于 TCP 传输的,所以在 IP 包头的协议部分是固定的,为 06(十六进制),表示协议是 TCP。如果客户端有多个网卡和多个IP,在填写源 IP 时,就需要系统判断应该使用哪一块网卡来发送包。这个时候就需要根据路由表规则,来判断哪一个网卡作为源 IP。在 Linux 操作系统,我们可以使用 route -n 命令查看当前系统的路由表。例如:
HTTP网页从请求到响应过程详解_第12张图片
根据上面的路由表,我们假设 Web 服务器是 192.168.10.200。判断过程如图:
HTTP网页从请求到响应过程详解_第13张图片
首先和第一条目的子网掩码进行 与运算,得到结果为 192.168.10.0,但与条目的 Destination 192.168.3.0不一致。再与第二条目与运算,结果为 192.168.10.0,与 Destination 192.168.10.0 匹配成功,所以将使用 eth1 网卡的 IP 地址作为 IP 包头的源地址。

再假设 Web 服务器的地址是 10.100.20.100,那么依然上面的路由表规则,判断后的结果是第三条目匹配。第三条目比较特殊,它目标地址和子网掩码都是 0.0.0.0,这表示默认网关,如果其他所有条目都无法匹配,就会自动匹配这一行。并且后续就把包发给路由器,Gateway 即是路由器的 IP 地址。

经过IP层处理后,报文格式大致如下图:
HTTP网页从请求到响应过程详解_第14张图片

网络接口层

加上IP头部后,接下来网络包还需要在 IP 头部的前面加上 MAC 头部。MAC 头部是以太网使用的头部,它包含了接收和发送方的网卡 MAC 地址等信息。mac头部很简单,只有3个字段:48位的目标MAC地址、48位的源MAC地址和16位的协议类型。

MAC 包头里的源 MAC 地址和目标 MAC 地址,用于两设备之间的传输。在 TCP/IP 协议栈里,MAC 包头的协议类型一般只使用:0800 ,IP 协议 和 0806 ,ARP 协议。MAC 地址是网卡生产时烧录到 ROM 里的,只要将这个值读取出来写到 MAC 头部源MAC就可以了。下一跳的IP地址可以根据路由表获得,在表中找到相匹配的条目就可以了。MAC地址也是根据查表,叫ARP缓存表。此时需要 ARP 协议解析下一跳IP的 MAC 地址。

ARP 协议会以广播的形式,对局域网内所有的设备询问IP对应的mac地址。如果对方和自己处于同一个子网中,那么通过上面的操作就可以得到对方的 MAC 地址。然后,我们将这个 MAC 地址写入 MAC 头部的目标mac。操作系统会把本次查询结果放到 ARP 缓存表备用。也就是说,在发包时:先查询 ARP 缓存,如果有对应的记录,就不需要发送 ARP广播 查询。当 ARP 缓存中不存在相关记录时,才发送 ARP 广播查询。在 Linux 系统中,可以使用 arp -a 命令来查看 ARP 缓存内容。

经过网络接口层处理后,报文格式大致如下图:
HTTP网页从请求到响应过程详解_第15张图片

IP 生成的网络包是存放在内存中的一串二进制数字信息,没有办法直接发送给对方。系统需要将数字信息转换为电信号,才能在网线上传输。负责执行这一操作的是网卡,要控制网卡还需要靠网卡驱动程序。网卡驱动从 IP 模块获取到包之后,会将其复制到网卡内的缓存区中,然后在开头加上报头和起始帧分界符,在末尾加上用于检测错误的帧校验序列。如图:
HTTP网页从请求到响应过程详解_第16张图片
起始帧分界符表示包起始位置的标记;末尾的 FCS(帧校验序列)用来检查包传输过程是否有损坏。最后网卡会将二进制数据转为电信号,通过网线发送出去。

中间网络设备

比特流顺着网线发出去以后,需要经过很多中间设备才能到达服务器。首先就要经过交换机。交换机主要是负责转发,将网络包原样转发到目的地。交换机工作在 MAC 层,也称为二层网络设备,当然也有三层交换机。

首先,电信号到达交换机的网线接口,交换机里的模块进行接收并将电信号转换为数字信号。然后通过包末尾的 FCS 校验错误,如果没问题则放到缓冲区。这部分操作基本和计算机的网卡相同,但交换机的工作方式和网卡不同。因为网卡本身有 MAC 地址,会核对收到的包目标 MAC 地址是不是发给自己的,如果不是则丢弃;而交换机的端口不核对接收方 MAC 地址,直接接收所有的包并存放到缓冲区中。这是和网卡不同的一点,交换机的端口没有 MAC 地址。

交换机将包存入缓冲区后,就会查询这个包的接收方 MAC 地址是否在 MAC 地址表中。交换机的 MAC 地址表主要包含两个信息:一个是设备的 MAC 地址;另一个是该设备连在交换机的哪个端口。
HTTP网页从请求到响应过程详解_第17张图片
如上图,交换机内维护着一张mac地址表,即mac地址与网线端口的映射表。收到包时,就会把mac地址和对应的端口写入表中,交换机根据mac地址表进行转发。

如果地址表没有接收方 MAC 地址的记录,可能是因为该设备还没有向交换机发过任何的包,或一段时间没有工作(比如关机)导致地址被从地址表中删除。这种情况下,交换机会将包转发到除了源端口之外的所有端口上,无论该设备连接在哪个端口上都能收到这个包。

那么这样做会发送大量的包,会不会造成网络拥塞呢?其实不用担心,因为发送了包之后目标设备会作出响应,有了响应包,交换机就可以将它的地址写入 MAC 地址表,下次就不需要把包发到所有端口了。而且以太网的设计本来就是将包发送到整个网络的,然后只有相应的接收者才会接收包,其他设备则会忽略这个包。局域网中每秒可传输上千个包,多出一两个包并无大碍。此外,如果接收方 MAC 地址是一个广播地址,那么交换机还是会将包发送到除源端口之外的所有端口。以下属于广播地址:

MAC 地址中的 FF:FF:FF:FF:FF:FF
IP 地址中的 255.255.255.255

数据包经过交换机后,紧接着到达路由器,并在此被转发到下一个中间设备。这一步转发的工作原理和交换机类似,也是通过查表判断包转发的方向。不过具体的操作流程,和交换机还是有区别的。因为路由器是基于 网络层 设计的,俗称三层网络设备,其各个端口都具有 MAC 地址和 IP 地址;而交换机是基于网络接口层设计的,俗称二层网络设备,交换机的端口不具有 MAC 地址。

路由器的端口具有 MAC 地址,同时还具有 IP 地址,从这个意义上来说,它和计算机的网卡是一样的。当转发包时,路由器端口会接收发给自己的数据包,然后路由表查询转发目标,再由相应的端口作为发送方将数据包发送出去。

首先,电信号到达网线接口部分,路由器中的模块会将电信号转成数字信号,然后通过包末尾的 FCS 进行错误校验。如果没问题则检查 MAC 头部中的接收方 MAC 地址,看看是不是发给自己的包,如果是就放到接收缓冲区中,否则就丢弃这个包。

完成数据包接收操作后,路由器会去掉 MAC 头部,MAC 头部的作用就是将包送达路由器,其中的接收方 MAC 地址就是路由器端口的 MAC 地址。因此,当包到达路由器之后,MAC 头部的任务就完成了,于是 MAC 头部就会被丢弃。接下来,路由器会根据 IP 头部中的内容进行包的转发。转发分为几个阶段,首先查询路由表判断转发目标。
HTTP网页从请求到响应过程详解_第18张图片
上图是一台华为路由器设备的路由表。判断转发目标的第一步,就是根据包的接收方 IP 地址查询路由表中的目标地址栏,以找到相匹配的记录。路由匹配和前面讲的一样,每个条目的子网掩码和 目标 IP 做 与运算,得到的结果与对应条目的目标地址进行匹配,如果匹配就会作为候选转发目标,如果不匹配就继续。如果找不到匹配路由,就会选择默认路由,路由表中子网掩码为 0.0.0.0 的记录表示“默认路由”。

匹配路由后,就会进入包的发送操作。路由器根据路由表的下一跳判断对方的地址。知道对方的 IP 地址之后,接下来需要通过 ARP 协议根据 IP 地址查询 MAC 地址,并将查询的结果作为接收方 MAC 地址。路由器也有 ARP 缓存,因此首先会在 ARP 缓存中查询,如果找不到则发送 ARP 查询请求。接下来是发送方 MAC 地址字段,这里填写输出端口的 MAC 地址。还有一个以太类型字段,填写 0080 (十六进制)表示 IP 协议。

网络包完成后,接下来会将其转换成电信号并通过端口发送出去。发送出去的网络包会通过交换机到达下一个路由器。接下来,下一个路由器会将包转发给再下一个路由器,经过层层转发之后,网络包就到达了最终的目的地。在网络包传输的过程中,源 IP 和目标 IP 始终不会变,变化的是 MAC 地址,因为需要在不同的中间设备中传输。

逆向拆包

数据包最终抵达了服务器,服务器会进行解包。数据包抵达服务器后,服务器会先检查数据包的 MAC 头部,查看是否和服务器自己的 MAC 地址符合,符合就接收包。接着继续查看数据包的 IP 头,发现 IP 地址符合,根据 IP 头中协议项,知道自己上层是 TCP 协议。接着查看 TCP 的头,里面有序列号,检查该序列包是不是需要的,如果是就放入缓存然后返回一个 ACK,否则丢弃。TCP头部里面还有端口号, Web服务正在监听这个端口号。于是,系统就知道了是 HTTP 进程的包,便把包发给 HTTP 进程。
HTTP网页从请求到响应过程详解_第19张图片

服务器的 HTTP 进程检查http头部,发现该请求是要访问一个页面,于是就把这个网页封装在 HTTP 响应报文里。HTTP 响应报文也需要经过 TCP、IP、MAC 头部的层层封装,不过这次源IP和目标IP调换了位置。封装好后从网卡出去,经过交换机转发到路由器,路由器就把响应数据包发到了下一个路由器,到了最后一跳路由器,路由器检查IP 头部发现是本局域网的设备,于是把包发给了内网交换机,再由交换机转发到客户端。

客户端收到了服务器的响应数据包后,也开始逆向解析,一直解析到 HTTP 响应报文后,然后交给浏览器去渲染页面,网页就这样显示出来了。最后,浏览器关闭了,向服务器发起了 TCP 四次挥手,至此双方的连接就断开了。

小结

OK,这就是从输入url到网页显示的全过程了,希望对正在学习《计算机网络》这门课程的同学有所帮助。

在《计算机网络·自顶向下》这部书中有更多相关内容,这本书也是我老师推荐我读的,确实不错,对于想深入了解计算机网络的值得一读。这本书目前最新的是第7版。为了方便大家学习,我已经将其打包挂在公众号上了,关注:极客随想。回复消息:计算机网络。即可获取。

你可能感兴趣的:(计算机网络,计算机网络,网络协议)