从输入 URL 到页面渲染发生了什么?比如在浏览器输入了 www.qq.com 后浏览器是怎么把最终的页面呈现,这是一个非常经典的面试题,不管是大公司还是小公司甚至前端或后端的面试中命中率都极高,因为涉及到的知识点和可挖掘的地方比较多,而且这中间几乎每一步都是可以优化的。文章很长,原作者分成了三个篇幅,分别从 网络通信 和页面渲染 两个方面描述
写在前面
URL从输入到页面渲染这整个过程可以分为 网络通信 和 页面渲染 两个方面,一般后端程序猿回答这个问题侧重网络通信就行了,但是前端页面渲染也得了解,总之回答的越详细分值越高
那么开始吧,这篇文章我们先来看网络通信方面,可能前端同学大家对网络方面的认知应该没有后端同学强,其实这道面试题最能突出自己的也是网络方面,因为它涉及到了很多网络通信原理的知识,所以这块咱们慢慢梳理
网络分层的由来
不晓得大家知不知道网络分层,网络其实有很多层,层与层之间又有好多协议存在,还有各种各样的数据包,这玩意干巴巴的,很没意思,这么多层太麻烦了,为什么有这么多层呢?为什么不直接一层呢?
起初计算机与计算机之间的通信只需要一根线就可以完成通信,但是世界那么大,那么多计算机,距离太远了,而且这线还老容易被无良的人偷偷剪断
后来就出来了无线网,虽然其中网关、路由之间也需要连线,但不是让每台计算机两两连接,而是一个区域为单位计算机相互连接通信
后来发现计算机之间的连线只能传送0/1信号,另一台计算并不知道那么多0/1代表什么,就像 010101010101111000111011010 你知道这一大串是什么意思吗,计算机也不知道,不同厂商生产的计算机连线实现通信也是很麻烦的,干脆定义一套规则吧,不管是哪个牌子的计算机,都必须遵守这套规则,这套规则就是我们经常说的 网络协议
哦哦,是在说 网络分层 ,不是讲 网络协议 ,继续继续,接着我们上面的话题,问题来了,计算机之间通过连线传送0/1信号的问题虽然规定了通信规则,但是除了像0/1这种无意义的信号之外,网络中还存在着其他各种各样的问题
- 两个计算机之间怎么进行识别?
- 怎么才能知道对方的地址?
- 不同计算机应用程序怎么知道是给自己传递的数据?
- 不同的通信数据格式怎么来规定等等一系列的问题
如果各种问题都写成一套协议来规定双方通信的规则,但是万一其中哪些规则通信中出现问题,影响到了其他规则,最常见的就是数据包,一个数据包中如果包含各种各样的协议
如果我们对网络进行分层,每一层负责一项具体的工作,然后把数据传送到下一层,那么往来通信和网络互联这一复杂的问题是不是就变得较为简单化了呢
TCP/IP五层模型
目前的网络层次可划分为 四层因特网协议栈 和 七层因特网协议栈 ,其实起初网络分层是标准的七层,也就是我们所说的 OSI 七层模型 ,参考模型是国际标准化组织 ISO 制定的一个用于计算机或通信系统间互联的标准体系,一般称为 OSI参考模型 或 七层模型
可能对网络有些了解的同学知道还有 TCP/IP 四层模型 和 TCP/IP 五层模型 ,这又是怎么出来的呢?
其实所谓的 TCP/IP 四层模型 和 TCP/IP 五层模型 是以 OSI 七层 优化而来,把某些层进行合并了,本质上还是相同的,OSI七层模型 太过细化,有一定的参考意义,但实现起来比较繁琐,相比较而言,TCP/IP模型 比较简洁,具有较强的实际应用价值
我们来看一个模型的图片 ( 网图侵删 )
TCP/IP 将计算机网络分成了四个层次,一般资料或教程里都是结合 OSI7层模型 和 TCP/IP4层模型,将计算机网络按照5层的模型来讲,5层模型只是为了方便介绍计算机网络原理而设计的,而在实际应用中还是 TCP/IP四层模型 ,这点大家要明白
这里我们同样用五层来解释,比较好理解些,当然,这里只能让大家脑海里有一个具体的网络分层结构的认知,作为面试回答了解这些足够,而后推荐大家继续深入,可以看相关的书籍和资料,此文也能够起到一个引导的作用
PS: 作为一个前端或者是后端,我们都是软件开发,所以侧重点放在网络层以上就可以了,物理层和数据链路层都是硬件相关的,所以这两个层下面不会过多叙述,了解即可
物理层(physical layer)
物理层,顾名思义,通过物理手段 ( 网线,光纤,无线 ) 将设备连接在一起,传输0/1电信号 ( 也叫比特流 ) ,就像我们上边讲到的计算机之间的物理连线
主要用来传输0/1信号,因为0/1信号没有任何的现实意义,所以用另一层用来规定不同0/1组合的意义
数据链路层(data link layer)
还是上面说的,010101010101111000111011010 ,像这么一串数据计算机并不知道是什么意思
下层的物理层不能规定不同0/1组合的信号代表什么意义,所以在数据链路层规定了一套协议,专门给0/1信号进行分组,规定不同的组代表的是什么意思,从而让双方计算机都能够进行识别,这个协议就是我们常说的 以太网协议
以太网协议
以太网协议规定一组电信号构成一个数据包,我们把这个数据包称为 帧 ,每一个帧由 标头 和 数据 两部分组成
帧的大小一般为 64 - 1518 个字节 较大的数据则需要分成多个桢
标头 Head ,18个字节组成,标头中包含这个 桢 是由谁发送、发送给谁这些信息,所以标头主要是一些说明数据 例如发送者/接受者等信息
数据 Data ,46-1500个字节组成,里面主要是发送者想给接收者的内容
把一台计算机的数据通过物理层和数据链路层发送给另外一台计算机,怎么标识对方以及怎么知道对方的地址呢? 唯一标示 MAC地址 出现了
MAC地址
进入网络的每一台计算机,都会有网卡接口,每一个网卡都会有一个唯一的地址,就是所谓的 MAC地址 ,它就是网络中每台计算机设备的唯一标识,是一串由48个字节组成的十六进制数,每台计算机在厂商生产出来的时候就标识好了,所以我们用 MAC地址 来标识对方
如上图所示,如计算机A知道了计算机B的MAC地址,然后计算机A想要给计算机B传送数据,虽然计算机A知道了计算机B的MAC地址,可是A要怎么给B传送数据呢?
计算机A不仅连着计算机B,而且计算机A也连接着计算机C和D,虽然计算机A知道计算机B的MAC地址,但是却不知道B是在哪一路上,所以为了解决这个问题,广播 这个概念就出现了
广播
在同一子网络,就是我们常说的局域网中,计算机通过广播来通信,即向同子网中全部计算机发送数据包,其它计算机根据数据包中接收者的 MAC地址 来判断是否接收数据包
通俗来讲,就是A会同时给B/C/D发送数据包,这个数据包中会包含着接收者的 MAC地址 信息,当B/C/D接收到了数据包,会取出数据包中的 MAC地址 与自身的 MAC地址 对比,如相同就接收这个数据包,否则就丢弃这个数据包 ( 丢包 ),这种方式我们称之为 广播
就像,你和女友在人群中走散了,你大喊一声她的名字,听到的人会自己匹配,是自己就会理会,不是自己就当你是傻子不理你
那么到了目前,我们知道了计算机之间的标示和如何通信,但是还有一个问题,要怎么知道对方的 MAC地址 呢 ?这又牵出了 ARP协议 ,通过 ARP协议 来得知对方的 MAC地址 ,这个协议是网络层的一个协议,所以我们暂且搁置,先接着往下看
网络层
看了物理层和数据链路层的作用,可能大家会觉得好像已经可以完成正常通信了,那么网络层又是做什么的呢?
其实我们所处的网络,是由无数个子网络 ( 局域网 ) 构成的,广播的时候,也只有同一个子网里的计算机能够收到,如过没有子网这种东西,计算机A通过广播的方式发一个数据包给计算机B,那么全世界所有的计算机都能收到这个数据包,然后进行对比再舍弃,那么多台计算机后果可想而知,子网也因此而产生
那么问题又来了,我们要怎么区分 Mac地址 是属于同一个子网的呢?假如是同一个子网,我们就用广播的形式把数据传送给对方,如果不是同一个子网的,我们就会把数据发给网关,让网关进行转发
怎么判断两台计算机是否在同一个子网中呢,这就是网络层干的事情,为了解决这个问题,就有了 IP协议 的概念
IP协议
IP协议 所定义的地址,就是我们常说的 IP地址 ,IP协议 有两个版本,ipv4 / ipv6,目前用的最多的还是 ipv4,这个地址由32位的二进制数组成,我们一般把它分成4段的十进制表示,地址范围在 0.0.0.0 ~ 255.255.255.255 ,这个我们应该都很常见
每一台想要联网的计算机都会有一个 IP地址 ,这个 IP地址 分为两部分,前面一部分代表网络,后面一部分代表主机,但是网络部分和主机部分所占用的二级制位数是不固定的
假如两台计算机的网络部分是一模一样的,我们就说这两台计算机是属于同一个子网 ( 局域网 ) 中,例如 192.168.17.1 和 192.168.17.2 , 假如这两个 IP地址 的网络部分为 24 位,主机部分为 8 位,那么他们的网络部分都为 192.168.17 , 所以我们说这两台计算机处于同一个子网中
问题又随之而来了,给我们两个 IP地址 ,鬼知道网络部分占几位,主机部分又占几位呢?
这就又引出了我们另一个关键词 子网掩码
子网掩码
子网掩码 和 IP地址 一样也是32位二进制数,但是它的网络部分规定全部为1,主机部分规定全部为0,也就是说假如上面那两个 IP地址 的网络部分为24位,主机部分为8位的话,那他们的子网掩码为
11111111.11111111.11111111.00000000 ,也就是 255.255.255.0
有了子网掩码,怎么来判断 IP地址 是否处于同一个子网中呢?
显然,知道了子网掩码,相当于我们知道了网络部分是几位,主机部分是几位,我们只需要把 IP地址 与他的子网掩码做一个 ( and ) 运算,然后把各自的结果进行比较就行了,如果比较的结果相同,则代表的是同一子网,否则不是同一子网
也就是说有了两台计算机的 IP地址 和 子网掩码 ,我们就可以判断他们是否处在同一子网当中了
假设他们处在同一子网当中,计算机A要和计算机B发送数据时,我们通过是 ARP协议 来得到计算机的 MAC地址
ARP协议
ARP协议 也是通过广播的形式,给同一个子网中每个电脑发送一个数据包,这个数据包会包含接收者的 IP地址,对方收到这个数据之后,会取出 IP地址 与自身的对比,相同则会把自己的 MAC地址 回复给对方,否则就丢弃这个数据包,这样计算机A就知道计算机B的 MAC地址 了
可能大家会问,知道了 MAC地址 后,发送数据是通过广播的形式发送,询问对方的 MAC地址 也是通过广播的形式来发送,那其他计算机怎么知道你是要传输数据还是询问 MAC地址 呢?
其实在询问 MAC地址 的数据包里,在对方的 MAC地址 这儿填的是一个特殊的 MAC地址 ,其他计算机看到这个特殊的 MAC地址 后,就知道广播是在询问了
如果两台计算机的 IP 不是处于同一个子网之中,这个时候我们就会把数据包发送给网关,然后让网关帮我们进行转发
运输层(transport layer)
通过 物理层 / 数据链路层 以及 网络层 的互相协调,我们成功的把数据从计算机A传到了计算机B,可是计算机B里面有各式各样的应用程序,计算机是如何知道这个数据是发给哪个应用程序的呢?
这个时候,端口 就上场了,当计算机A传输给计算机B的时候,还得指定一个端口,以供特定的应用程序来接收处理,作为程序员的我们对端口就更熟悉了,端口范围:0~65535,其中前1023个端口被系统占用
那么也就是说,传输层的功能就是建立端口到端口的通信,而相比之下网络层的功能是建立主机到主机的通信
有了 IP 和 端口 ,我们才能准确通信,我们输入的IP有些并没有指定端口号,其实是有些传输协议,设定了一些默认端口,例如 HTTP 默认是80,HTTPS 默认是443,这些端口信息也会包含在数据包里面
传输层最常见了两大协议就是 TCP协议 和 UDP协议
UDP协议
UDP协议 全称是用户数据报协议,是一种无连接的协议,与TCP协议一样用于处理数据包
UDP数据包分 标头 (8个字节) 和 数据 (加标头不超过65535个字节), UDP数据包放在IP数据包的 数据 中,标头主要包括发出端口和接收端口
UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的
UDP特点
面向无连接
- UDP 想发数据就可以开始发送了,不需要连接,它只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接操作
- 在发送端,应用层将数据传递给传输层的 UDP 协议,UDP 只会给数据增加一个 UDP 头标识下是 UDP 协议,然后就传递给网络层了
- 在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作
- 有单播、多播、广播
- UDP 不止支持一对一的传输方式,同样支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能
面向报文
- 发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层
- UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界
- 因此,应用程序必须选择合适大小的报文
不可靠性
- 不可靠性首先体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠
- 收到什么数据就传什么数据,并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了
- 网络环境时好时坏,但 UDP 没有拥塞控制,一直会以恒定的速度发送数据,即使网络条件不好,也不会对发送速率进行调整,这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景 ( 比如电话会议 ) 就需要使用 UDP 而不是 TCP
头部开销小,传输数据报文高效
- UDP 头部包含了以下几个数据
- 两个十六位的端口号,分别为发出端口和接收端口
- 整个数据报文的长度
- 整个数据报文的检验和(IPv4 可选字段),该字段用于发现头部信息和数据中的错误
- 所以UDP 的头部开销小,只有8字节,相比 TCP 的至少20字节要少得多,在传输数据报文时是很高效的
TCP协议
当一台计算机想要与另一台计算机通讯时,两台计算机之间的通信需要畅通且可靠,这样才能保证正确收发数据
- 例如你想查看网页或查看电子邮件时,希望完整且按顺序查看网页,而不丢失任何内容
- 又例如当你下载文件时,希望获得的是完整的文件,而不仅仅是文件的一部分
如果数据丢失或乱序,都不是你希望得到的结果,于是就用到了 TCP
TCP协议 全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP 是面向连接的、可靠的流协议,什么是流?流就是指不间断的数据结构,可以把它想象成排水管中的水流
TCP特点
面向链接
- 面向连接,是指发送数据之前必须在两端建立连接,建立连接的方法就是 三次握手,这样能建立可靠的连接,为数据的可靠传输打下了基础
仅支持单播传输
- 每条TCP传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式
面向字节流
- TCP不像UDP一样那样一个个报文独立传输,而是在不保留报文边界的情况下以字节流方式进行传输
可靠传输
- 对于可靠传输,判断丢包,误码靠的是TCP的段编号以及确认号,TCP为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收
- 然后接收端实体对已成功收到的字节发回一个相应的确认(ACK),如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传
提供拥塞控制
- 当网络出现拥塞的时候,TCP 能够减小向网络注入数据的速率和数量,缓解拥塞
全双工通信
- TCP允许通信双方的应用程序在任何时候都能发送数据,因为TCP连接的两端都设有缓存,用来临时存放双向通信的数据
- 当然,TCP可以立即发送一个数据段,也可以缓存一段时间以便一次发送更多的数据段(最大的数据段大小取决于MSS)
TCP三次握手
三次握手建立连接,为方便理解,仿一次电面
- 小李 (客户端):您好,您是xx的面试官吗?
- 面试官 (服务端):嗯嗯,是的,你是昨天投简历的小李吗?
- 小李 (客户端):嗯嗯,是的,我是
接着,小李和面试官开始愉快的侃起了大山
三次握手流程如下
- 第一次握手 客户端向服务端发送连接请求报文段,该报文段中包含自身的数据通讯初始序号,请求发送后,客户端便进入 SYN-SENT 状态
- 第二次握手 服务端收到连接请求报文段后,如果同意连接,则会发送一个应答,该应答中也会包含自身的数据通讯初始序号,发送完成后便进入 SYN-RECEIVED 状态
- 第三次握手 当客户端收到连接同意的应答后,还要向服务端发送一个确认报文,客户端发完这个报文段后便进入 ESTABLISHED 状态,服务端收到这个应答后也进入 ESTABLISHED 状态,此时连接建立成功
出现三次握手的原因是为了 防止出现失效的连接请求报文段被服务端接收的情况,从而产生错误
TCP四次挥手
四次挥手断开链接,接着仿电面
- 面试官 (主动方):嗯,你的情况我这边了解了,等通知吧 ( 我想挂了 )
- 小李 (被动方):嗯嗯,好的 ( 这就想挂了?我还没侃够 )
- 小李 (被动方):那希望有机会能和您一块共事 ( 拜拜吧您嘞 )
- 面试官 (主动方):嘀…嘀…嘀…嘀
四次挥手流程如下
- 第一次挥手 若客户端 A 认为数据发送完成,则它需要向服务端 B 发送连接释放请求
- 第二次挥手 B 收到连接释放请求后,会告诉应用层要释放 TCP 链接,然后会发送 ACK 包,并进入 CLOSE_WAIT 状态,此时表明 A 到 B 的连接已经释放,不再接收 A 发的数据了,但是因为 TCP 连接是双向的,所以 B 仍旧可以发送数据给 A
- 第三次挥手 B 如果此时还有没发完的数据会继续发送,完毕后会向 A 发送连接释放请求,然后 B 便进入 LAST-ACK 状态
- 第四次挥手 A 收到释放请求后,向 B 发送确认应答,此时 A 进入 TIME-WAIT 状态,该状态会持续 2MSL(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃)时间,若该时间段内没有 B 的重发请求的话,就进入 CLOSED 状态,当 B 收到确认应答后,也便进入 CLOSED 状态
为何客户端最后还等待2MSL
客户端需要保证最后一次发送的 ACK 报文到服务器,如果服务器未收到,可以请求客户端重发,这样客户端还有时间再发,重启 2MSL 计时
TCP/IP的并发限制
其实浏览器对同一域名下并发的 TCP 连接是有限制的(2-10个不等)
而且在 HTTP1.0 中往往一个资源下载就需要对应一个 TCP/IP 请求
UDP协议和TCP协议的区别
对比 | UDP | TCP |
---|---|---|
是否连接 | 无连接 | 面向连接 |
是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
连接个数 | 支持一对一,一对多,多对一和多对多通信 | 只能一对一通信 |
传输方式 | 面向报文 | 面向字节流 |
首部开销 | 首部开销小,仅8字节 | 首部最小20字节,最大60字节 |
适用场景 | 适用于实时应用 ( IP电话、视频会议、直播等 ) | 适用于要求可靠传输的应用,例如文件传输 |
- TCP向上层提供面向连接的可靠服务 ,UDP向上层提供无连接不可靠服务
- 虽然 UDP 并没有 TCP 传输来的准确,但是也能在很多实时性要求高的地方有所作为
- 对数据准确性要求高,速度可以相对较慢的,可以选用 TCP
应用层(Application layer)
应用层是最接触用户的,上面几层我们收到了传输层收到的数据,TCP/UDP协议可以传递各种程序的数据包,就像邮箱/网页/FTP等等,所以就需要不同的协议来规定数据的格式,收到后才能渲染解读,应用层就是由这些协议构成,它的数据包放在UDP包/TCP包的 数据 中
我们遨游网络时经常用到的 HTTP 协议、文件传输用的 FTP 协议、电子邮件发送的 SMTP、域名解析的 DNS 协议、远程登录的 Telnet 协议等等都是属于应用层的
还有Socket,它是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作封装成几个简单的接口供应用层调用,从而实现进程在网络中的通信
上面我们已经基本了解到了计算机的一些通信基础,可以说到目前为止从一个IP到通信结束都已经知道了,但是我们输入的是域名不是IP,那么它是怎么变成IP通信的呢?这就要详细说说 DNS 了
DNS
DNS是什么
Domain Name System 简写 DNS ,翻译过来就是域名系统的意思,它是一种组织成域层次结构的计算机和网络服务命名系统,用于 TCP/IP 网络,作为将域名和IP地址相互映射的一个分布式数据库,它所提供的服务是用来将 主机名 和 域名 转换为 IP地址 的工作
简单来说,IP地址 就像门牌号一样,我们在输入域名访问网站时,数据服务器是不认识你这个域名的,它只认识IP,你的域名会通过 DNS服务器 解析成IP值,通过这个门牌号 (IP值) 向数据服务器查找你的网站数据并给你返回到浏览器上
为什么需要DNS
上面我们说,网络通讯大部分是基于TCP/IP的,而TCP/IP是基于IP地址的,所以计算机在网络上进行通讯时只能识别如 252.94.131.12 之类的IP地址,而不能认识域名
我们没办法记住10个以上IP地址的网站 ( 你要说记性好那俺就乖乖闭嘴了😄 ),一般我们访问网站时,更多的是在浏览器地址栏中输入域名,就能看到所需要的页面,这是因为有一个叫 DNS服务器 的计算机自动把我们的域名 翻译 成了相应的IP地址,然后通过 IP地址 返回所对应的网页