经典面试题之一,这次得搞得明明白白的,顺便把计网也复习复习。
首先感谢知乎的up主:撒网要见鱼,这是他的原文,本篇文章也是基于他的文章总结启发而来,主要就是记录记录笔记。
面试前复习
- 浏览器输入url,查看缓存,解析域名,涉及dns相关知识
- dns 使用udp,占53号端口
- dns服务器分为四种 本地域名服务器、权威域名服务器、顶级域名服务器、根域名服务器
- dns查询分为两种方式,递归查询,迭代查询
- 查询到ip地址,进行tcp链接
- tcp面向连接,可靠传输,保证数据包无错、不重复、不缺失、按序到达
- 一对一传输、全双工、面向字节流、有发送和接收缓存
- 三次握手、四次挥手
- 拥塞控制:慢启动、拥塞避免、快重传、快恢复
- 生成HTTP数据包
- http是应用层面向事务的协议,能够传输文本、声音、图像等各种多媒体文件
- http的持久连接分为非流水线和流水线方式,http/1.1默认使用流水线的持久连接
- http请求报文:有方法、url、版本、首部字段名和值、实体主体
- http响应报文:有版本、状态码、短语、首部字段名和值、实体主体
- 封装TCP报文
- 封装成ip数据包
- 报头(ipv4 20字节,ipv6 40字节),报头里存储了源ip和目的ip,tcp\udp报头里存储了源和目标端口
- 数据可能过长会被分片,因此有标识字段,相同标识号的分组为同一数据的不同部分。mf(more fragment) = 1表示后面还有分片,mf = 0表示为最后一个分片。df(dont fragment) = 0时才可以分片。片偏移字段用于表示当前数据在原始数据的起始位置
- 报头的总长度字段包括报头和数据
- ipv4 报文首部长度单位4B,总长度单位为1B(一共16位,最大65535B),片偏移单位为8B
- 进行分组转发
- 路由器检查路由表
- 先提取出目的ip,记为D
- 判断是否能够直接交付,将路由器各个直接相连的网络逐个检查,将各个网络的子网掩码与D进行与操作,查看网络号是否匹配。如果匹配则直接交付,否则间接交付,不匹配则执行下一条
- 检查路由表里是否有目的地址为D的特定主机路由,如果有则转发给路由表的下一条路由器,如果没有则执行下一条
- 将路由表的每一行(目的网络地址,子网掩码,下一条地址)的子网掩码和D相与,如果结果和目的网络地址相匹配,则发往对应的下一条路由器,如果都不匹配否则进行下一条
- 如果路由器有默认路由,则将分组转发个路由表中指明的默认路由器,如果没有则报告转发分组出错
- 内部网关协议IGP(一般有RIP[routing information protocol]路由信息协议、OSPF[Open Shortest Path First]开放最短路径优先)、外部网关协议EGP(BGP[border gateway protocol]边界网关协议)
- RIP协议
- RIP协议路由器每次和直接相邻路由器交换自己所有的路由表,其中用跳数表示经过的路由器个数,最大个数为15个,当为16时表示不可达。限定了网络规模,最大距离为15
- 正常情况下每隔30秒更新一次
- RIP协议最终是收敛的,因为每隔一次交换就能够知道距离自己条数加一的路由信息
- 当180秒还没有收到相邻路由器的更新路由表时,将该相邻路由器设为不可达,即把距离设为16
- 特点是收敛快,坏消息传的慢(180秒才超时),应用层协议,使用UDP传送数据,默认520端口,选择的路径不一定是时间最短的,但是是具有最少路由器的路径
- 使用的是距离向量协议
- OSPF协议
- OSPF向本自治系统中所有的路由器发送消息,使用洪泛法
- 发送的消息是与本路由器相邻的所有路由器的链路状态
- 只有链路状态发生变化时才使用洪泛法向所有路由器发送此消息,并且更新过程收敛快,不会出现RIP协议“坏消息传的慢”的问题
- OSPF是网络层协议,使用IP数据报传送,RIP是应用层协议,用UDP传送
- 使用Dijkstra计算最短路径
- 使用链路状态协议
- BGP协议
- 使用路径向量路由选择协议,属于应用层协议,使用TCP传输
- 每个自治系统要选择一个路由器作为该自治系统的“BGP发言人”,与其他自治系统的发言人建立TCP连接,交换路由信息
- BGP发言人除了运行BGP协议外,还要运行IGP协议
- 交换的信息为和本节点直接相邻的路由器
- 首次运行时交换整个路由表,非首次是只交换更新的部分
- RIP协议
- 分组向目的地址转发,靠ARP协议找到目标路由器或主机MAC地址
- 数据链路层
- 停止-等待协议,发送窗口=1,接收窗口=1,效率低
- 后退N帧协议,发送窗口>1,接收窗口=1
- 发送方一次可以发送N个帧,接收方一次只能接收一个帧,并且按序接收,返回ACKn,表示n之前的帧都已收到,期望下次收到n+1号帧,因此可以累计收到多个正确帧后再发送最后一个序号的ACK。
- 若中间某个序号i没有收到ACK,或者超时,发送方需要将i号以及以后的所有的帧再次重发一遍
- 若采用N个比特对帧编号,则发送方的窗口大小为1<= Wt<=2^n - 1
- 传输信道质量很差,误码率很高时,该方法不一定优于停止等待协议
- 选择重传协议,发送窗口>1,接收窗口>1
- 发送方对接收到的nak帧或超时帧进行重传
- 接收方窗口Wr,发送方窗口Wt,满足Wtmax + Wrmax <= 2^n,n为帧编号的比特数。
- 接收方窗口应该小于等于发送方窗口,当接收窗口最大值时Wr = Wr = 2^(n-1)
- 数据链路层的可靠传输通常使用确认和超时重传两种机制来完成。自动重传请求(auto repeat reQuest ARQ)分为三种,分别为停止等待、后退N帧、选择重传
- -
- 数据链路层
- 路由器检查路由表
大纲
主要有以下几个部分,并不会所有的部分都详细记录,主要记录和网络相关的部分
从浏览器接收url到开启网络请求线程
- 多进程的浏览器
- 多线程的浏览器内核
- 解析URL
- 网络请求都是单独的线程
- 更多
开启网络线程到发出一个完整的http请求
- DNS查询得到IP
- tcp/ip请求
- 五层因特网协议栈
从服务器接收到请求到对应后台接收到请求
负载均衡- 后台的处理
后台和前台的http交互
- http报文结构
- cookie以及优化
- gzip压缩
- 长连接与短连接
- http 2.0
- https
单独拎出来的缓存问题,http的缓存
- 强缓存与弱缓存
- 缓存头部简述
- 头部的区别
解析页面流程
- 流程简述
- HTML解析,构建DOM
- 生成CSS规则
- 构建渲染树
- 渲染
- 简单层与复合层
- Chrome中的调试
- 资源外链的下载
- loaded和domcontentloaded
CSS的可视化格式模型
- 包含块(Containing Block)
- 控制框(Controlling Box)
- BFC(Block Formatting Context)
- IFC(Inline Formatting Context)
- 其它
JS引擎解析过程
- JS的解释阶段
- JS的预处理阶段
- JS的执行阶段
- 回收机制
或者简单点,这么看:
1. 从浏览器接收url到开启网络请求线程(这一部分可以展开浏览器的机制以及进程与线程之间的关系)
2. 开启网络线程到发出一个完整的http请求(这一部分涉及到dns查询,tcp/ip请求,五层因特网协议栈等知识)
3. 从服务器接收到请求到对应后台接收到请求(这一部分可能涉及到负载均衡,安全拦截以及后台内部的处理等等)
4. 后台和前台的http交互(这一部分包括http头部、响应码、报文结构、cookie等知识,可以提下静态资源的cookie优化,以及编码解码,如gzip压缩等)
5. 单独拎出来的缓存问题,http的缓存(这部分包括http缓存头部,etag,catch-control等)
6. 浏览器接收到http数据包后的解析流程(解析html-词法分析然后解析成dom树、解析css生成css规则树、合并成render树,然后layout、painting渲染、复合图层的合成、GPU绘制、外链资源的处理、loaded和domcontentloaded等)
7. CSS的可视化格式模型(元素的渲染规则,如包含块,控制框,BFC,IFC等概念)
8. JS引擎解析过程(JS的解释阶段,预处理阶段,执行阶段生成执行上下文,VO,作用域链、回收机制等等)
9. 其它(可以拓展不同的知识模块,如跨域,web安全,hybrid模式等等内容
从浏览器接受url到开启网络请求线程
这里会设计到浏览器开启线程处理请求,这点不说,先来看url解析
解析URL
输入URL后,会进行解析(URL的本质就是统一资源定位符)
URL一般包括几大部分:
- protocol,协议头,譬如有http,ftp等
- host,主机域名或IP地址
- port,端口号
- path,目录路径
- query,即查询参数
- fragment,即#后的hash值,一般用来定位到某个位置
清晰易懂,需要记住protocol://host:port/path?query#fragment大概就是这样了
开启网络线程到发出一个完整的http请求
到这步,浏览器就要开始发送请求了,但是在发送请求之前,需要进行诸如dns解析
,tcp/ip建立链接
,五层因特网协议栈
之类的操作。
首先,第一步就是进行dns解析。此处依次分为如下几步:
- 检查浏览器DNS缓存
- 检查本地DNS缓存
- 检查HOST文件
- 向DNS域名服务器查询
DNS查询用的是UDP协议,DNS协议工作在应用层,使用53号端口,UDP协议工作在传输层
TCP/IP请求
http的本质就是tcp/ip请求
首先TCP协议有以下特点:
- 面向连接,可靠传输(无差错,不丢失,不重复且有序)
- 每个TCP连接只能有两个端点,即点对点,一对一连接
- TCP提供全双工通信,所以TCP连接的两端都有缓存
- 发送方缓存存储:1.需要发送但还未发送的数据 2.已发送,但还未收到确认的数据
- 接收方缓存存储:1.按序到达,但未被应用程序读取的数据 2.未按序到达的数据
- 工作在传输层(传输层的作用是负责应用程序之间的通信,是端到端的通信,这也是为什么TCP报文首部固定字段【20字节】中最先存的就是源端口号和目的端口号)
需要了解3次握手规则建立连接以及断开连接时的四次挥手
tcp将http长报文划分为短报文,通过三次握手与服务端建立连接,进行可靠传输
三次握手的步骤:(抽象派)
客户端:喂,你听得到吗?
服务端:我听得到呀,你听得到我吗?
客户端:我能听到你,今天balabala……
从这个连接建立的过程,有以下几点知识点:
- 客户机向服务器发送一个连接请求,这时要将SYN(为1表示该报文为连接请求或者连接接收报文)标识为1,同时随机选择一个起始序列号seq = x
- 不能携带数据,但要消耗一个序号
- 服务器接收到连接请求后,返回确认报文,设置SYN = 1,ACK = 1,seq = y(随机设置),ack = x + 1(表示x已收到,期待x + 1的到来),表示确认。
- SYN = 1, ACK = 0 表示连接请求报文,SYN = 1,ACK = 1 表示连接接收报文
- SYN = 1时,报文段不能有数据部分,而且要消耗一个序号
- seq为序号字段,表示本报文数据的第一个字节的序号,不过三次握手前两次中,是不允许带数据的
- ack为确认号,表示期望收到对方下一个报文的数据的第一个字节的序号,也就是前面的数据都收到了
- 这步时,服务器已经开始给连接分配缓存和变量了,而客户机是在第三步才分配,所以服务器易收到SYN洪泛攻击
- 客户机收到服务器的连接接收报文,还要向服务器给出确认,并且也要给连接分配缓存和变量。此时返回ACK = 1,seq = x + 1,ack = y + 1,
此时可以携带数据
- 客户机是在第三次握手时才分配连接缓存和变量
- 由于此时不用将SYN设置为1,所以报文可以携带数据
- 如果不携带数据,则不用消耗序号
- 之后就可以愉快的传输数据了,记得ACK得一直设为1
为何不是二次握手,四次握手?
简单来说不是二次握手是这样:
1:A发,B收, B知道A能发
2:B发,A收, A知道B能发收
3:A发,B收, B知道A能收
而不用四次或更多握手,是因为:
三次是保证双方互相明确对方能收能发的最低值。
理论上讲不论握手多少次都不能确认一条信道是“可靠”的,但通过3次握手可以至少确认它是“可用”的,再往上加握手次数不过是提高“它是可用的”这个结论的可信程度。
然后,待到断开连接时,需要进行四次挥手(因为是全双工的,所以需要四次挥手)
四次挥手的步骤:(抽象派)
主动方:我已经关闭了向你那边的主动通道了,只能被动接收了
被动方:收到通道关闭的信息
被动方:那我也告诉你,我这边向你的主动通道也关闭了
主动方:最后收到数据,之后双方无法通信
详细有以下知识点:
- 客户端请求关闭连接,发送FIN = 1, seq = u
- 服务器接收到客户端的关闭请求,返回ACK,返回ACK = 1, seq = v, ack = u + 1
- 此时服务器可以关闭读通道了,因为客户端不会再发送数据了
- 此时服务器还可以继续发送数据
- 服务端接收到ACK后,关闭写通道,它可以不再写数据了
- 服务器数据发送数据完毕,也要关闭连接了,发送FIN = 1, ACK = 1, seq = w, ack = u + 1
- 客户端收到该消息后,可以关闭读通道了,因为服务器不会再发送数据了
- 客户端发送最后的ACK,服务端关闭写通道,关闭连接,发送ACK = 1, seq = u + 1, ack = w + 1
- 客户端发送最后的ACK后还要等待2MSL。1.护送最后的ACK,避免服务端没收到,又发来FIN重传。2.假如连接立马释放,而客户端和服务器的ip和端口刚好被别的客户端和服务器占用,则新的客户端和服务器会收到不属于它们的报文。为此等待2MSL,使得链路中的原始报文都消失掉。2MSL的原因是,1MSL等待一方报文消失,1MSL等待报文ACK消失
五层因特网协议栈
七层协议中各层的主要功能和协议
OSI的七层 | 功能 | TCP/IP协议族 |
---|---|---|
应用层 | 文件传输、电子邮件、文件服务、虚拟终端 | TFTP、HTTP、SNMP、FTP、SMTP、DNS、TELNET、DHCP、RIP(路由信息协议)、BGP |
表示层 | 数据格式化、代码转换、数据加密、压缩解压 | 没有 |
会话层 | 解除或建立与别的节点的联系 | 没有 |
传输层 | 提供端对端的接口 | TCP、UDP |
网络层 | 为数据包选择路由 | IP、ICMP、OSPF、IGMP |
数据链路层 | 传输有地址的帧以及错误检测功能 | SLIP、CSLIP、PPP、ARP、RARP、MTU |
物理层 | 以二进制数据形式在物理媒体上传输数据 | ISO2110、IEEE802、IEEE802.2 |
五层协议:
1.应用层(dns,http) DNS解析成IP并发送http请求
2.传输层(tcp,udp) 建立tcp连接(三次握手)
3.网络层(IP,ARP) IP寻址
4.数据链路层(PPP) 封装成帧
5.物理层(利用物理介质传输比特流) 物理传输(然后传输的时候通过双绞线,电磁波等各种介质)
服务器接收到请求到对应后台接收到请求
负载均衡
nginx有ip hash, least_conn,还可以设置权重来实现负载均衡
后台处理
- 验证,安全拦截,跨域拦截
- 通过验证后才会进入后台实际代码
- 处理完毕后返回http响应包
再往后就是浏览器处理响应包,前端渲染之类的了,不是我关心的重点了,就不看了。主要看下OSI七层模型,每层的重点吧。
网络层
- 列表内容