TCP/IP 原理体系结构
- 应用层:解决通过应用进程的交互 来实现特定网络应用的问题
- 运输层(传输层):解决进程 之间基于网络通信的问题
- 网络层:解决分组在多个网络上传输(路由)的问题
- 数据链路层:解决分组在一个网络或一段链路上传输的问题
- 物理层:解决用何种信号传输比特的问题
输入浏览器地址到首页渲染经历了什么
- 对
URL
进行解析,从而生成发送给Web
服务器的请求信息。 - 主机的DNS客户端进程 向DNS服务器 发生DNS查询请求报文,问该域名对应的ip地址是多少
- DNS查询请求报文 使用运输层的UDP协议封装,目的端口号设置成53
- DNS服务器 收到该请求报文,因为目的端口号为53,将其交给DNS服务器端进程
- DNS服务器端进程 查找对应的ip地址,然后发送DNS响应报文,告诉该域名对应的ip地址
- 主机的DNS客户端进程收到该数据报并解析后,就知道对应的ip地址了
- 然后准备发送 HTTP请求报文,经历 TCP 三次握手
- 第一次握手:客户端发送 SYN = 1, 序列号初始化为一个随机数的消息
- 第二次握手:服务端发送 SYN = 1, ACK = 1, 确认应答号初始化为客户端随机数 + 1, 序列号为服务端随机数的消息
- 第三次握手:客户端发送 ACK = 1, 确认应答号为服务端随机数 + 1的消息
- 然后主机的HTTP客户端进程 向web服务器发送HTTP请求报文,问首页的内容是什么
- HTTP请求报文 通过TCP协议封装,目的端口号为80
- web服务器的HTTP服务器端进程 收到该请求报文,返回HTTP响应报文,里面包含首页内容
- 处理 HTML 标记并构建 DOM 树。
- 处理 CSS 标记并构建 CSSOM 树。
- 将 DOM 与 CSSOM 合并成一个渲染树。
- 根据渲染树来布局,以计算每个节点的几何信息。
- 将各个节点绘制到屏幕上。
域名系统DNS
- 每级域名用
.
隔开,级别低的域名在左边,级别高的在右边
域名服务器四种类型
- 根域名服务器 :最高层次的域名服务器。共有13个(每个实际是服务器集群),每个根域名服务器知道所有的顶级域名服务器 的域名及其ip地址。根域名服务器通常不直接解析域名 而是返回该域名所属顶级域名服务器的IP地址
- 顶级域名服务器 :负责管理在该服务器注册的所有二级域名 ,收到DNS查询请求时给出相应的回答(可能是最后结果,也可能是下一级权限域名服务器的IP地址)
- 权限域名服务器 :管理某个区的域名,每一个主机的域名都必须在某个权限域名服务器中登记
- 本地域名服务器 :不属于上述域名服务器的登记结构,本地域名服务器起着代理的作用,会把DNS请求报文转发到上述域名服务器的等级结构中
域名解析的过程
- 主机向本地域名服务器 进行递归查询
- 本地域名服务器 向根域名服务器 进行迭代查询
- 根域名服务器 告诉本地域名服务器 下一次应查询的顶级域名服务器的IP地址
- 本地域名服务器 向顶级域名服务器 进行迭代查询
- 顶级域名服务器 告诉本地域名服务器 下一次应查询的权限域名服务器的IP地址
- 本地域名服务器 向权限域名服务器 进行迭代查询
- 权限域名服务器 告诉本地域名服务器所查询域名的IP地址
- 本地域名服务器告诉主机所查询域名的IP地址
HTTP
HTTP/1.0
- 采用短连接,每次浏览器请求一个文件都要建立TCP连接,收到响应后立即关闭连接
HTTP/1.1
- 使用长连接,建立连接后不会立即关闭,等到通信双方其中一方主动提出关闭才关闭
- 支持管道网络传输,只要第一个请求发出去了,不必等其回来,就可以发送第二个请求
缺点(5):
- 请求 / 响应头部(header)未经压缩就发送,首部信息越多延迟越大
- 发送冗长的首部。每次互相发送相同的首部造成的浪费较多
- 仍然存在服务器队头阻塞,如果服务器响应慢,会招致客户端一直请求不到数据
- 没有请求优先级控制
- 请求只能从客户端开始,服务器只能被动响应
HTTP/2
HTTP/2 协议是 基于 HTTPS 的,所以 HTTP/2 的安全性也是有保障的
- 头部压缩 :如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮你消除重复的部分。
- 二进制格式 :收到报文后,无需再将明文的报文转成二进制,而是直接解析二进制报文,这增加了数据传输的效率
- 并发传输 :出了 Stream 概念,多个 Stream 复用在一条 TCP 连接,Stream 里可以包含 1 个或多个 Message,Message 对应 HTTP/1 中的请求或响应 ,由 HTTP 头部和包体构成。Message 里包含一条或者多个 Frame,Frame 是 HTTP/2 最小单位 ,以二进制压缩格式存放 HTTP/1 中的内容(头部和包体)。针对不同的 HTTP 请求用独一无二的 Stream ID 来区
- 服务器推送 :服务端不再是被动地响应,可以主动 向客户端发送消息。客户端和服务器双方都可以建立 Stream, Stream ID 也是有区别的,客户端建立的 Stream 必须是奇数号,而服务器建立的 Stream 必须是偶数号。
缺点:
- TCP层队头阻塞 :TCP 层必须保证收到的字节数据是完整且连续 的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来。
HTTP/3
HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP ,基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输
- 无队头阻塞 :当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响,因此不存在队头阻塞问题。这与 HTTP/2 不同,HTTP/2 只要某个流中的数据包丢失了,其他流也会因此受影响。
- 更快的连接建立 :QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的"记录",再加上 QUIC 使用的是 TLS/1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商
- 连接迁移 :基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接。QUIC 协议没有用四元组的方式来"绑定"连接,而是通过连接 ID 来标记通信的两个端点,客户端和服务器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以"无缝"地复用原连接,消除重连的成本,没有丝毫卡顿感,达到了连接迁移的功能。
HTTP 缓存
- 强制缓存 :浏览器决定是否使用缓存
Cache-Cotrol
: 响应字段,一个相对时间,由请求资源的时间和过期时间决定,优先级高Expires
: 响应字段,一个绝对时间,优先级低
- 协商缓存 :与服务器协商是否使用缓存
- 第一组:请求头:
If-Modified-Since
保存上一次的最后修改时间,响应头:Last-Modified
响应资源最后修改时间,优先级低 - 第二组:请求头:
If-None-Match
保存上一个唯一标识,响应头:ETag
唯一标识响应资源,优先级高
- 第一组:请求头:
HTTPS
HTTPS 在 HTTP 与 TCP 层之间加入了 SSL/TLS
协议
HTTPS 解决了 HTTP 的哪些问题?
- 通过混合加密 保证了信息的机密性。
- 通过摘要算法计算出内容的哈希值 保证了信息的完整性。
- 通过将服务器公钥放入到数字证书中,保证了信息不会被冒充。
混合加密
HTTPS 采用的是对称加密 和非对称加密结合的「混合加密」方式
非对称加密 采用私钥加密,公钥解密 保证消息不会被冒充
加密是对内容的哈希值进行加密
HTTPS 是如何建立连接的?
SSL/TLS 协议基本流程:
- 客户端向服务器索要并验证服务器的公钥。
- 双方协商生产「会话秘钥」。
- 双方采用「会话秘钥」进行加密通信。
RSA 加密流程
- 客户端发起加密请求:Client Hello::发送客户端支持的 TLS 协议版本 、客户端生产的随机数 、客户端支持的密码套件列表(3)
- 服务端返回响应:Server Hello::发送确认 TLS 协议版本 ,如果浏览器不支持,则关闭加密通信、服务器生产的随机数 、确认的密码套件列表 、Server Certificate::服务器的数字证书Server Hello Done:: 表示打招呼完毕(4)
- 客户端通过CA 公钥确认服务器的数字证书的真实性 ,没有问题,从数字证书中取出服务器的公钥 ,然后使用它加密报文,向服务器发送信息:Client Key Exchange::一个随机数 ,会被服务器公钥加密、Change Cipher Spec::加密通信算法改变通知 ,表示随后的信息都将用「会话秘钥」加密通信、Encrypted Handshake Message(Finishd)::客户端握手结束通知 ,同时把之前所有内容的发生的数据做个摘要,用来供服务端校验。(3)
- 服务器收到客户端的第三个随机数之后,通过协商的加密算法,计算出本次通信的「会话秘钥」 ,向客户端发送最后的信息:Change Cipher Spec::加密通信算法改变通知 ,表示随后的信息都将用「会话秘钥」加密通信、Encrypted Handshake Message::服务器握手结束通知 ,同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。(2)
使用 RSA 密钥协商算法的最大问题是不支持前向保密: 一旦服务端的私钥泄漏了,过去被第三方截获的所有 TLS 通讯密文都会被破解。
CA 签发证书的过程,如上图左边部分:
- 首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
- 然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
- 最后将 Certificate Signature 添加在文件证书上,形成数字证书;
客户端校验服务端的数字证书的过程,如上图右边部分:
- 首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
- 通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密 Certificate Signature 内容,得到一个 Hash 值 H2 ;
- 最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。
ECDHE 加密流程
- 客户端发送消息:Client Hello::客户端使用的 TLS 版本号 ,支持的密码套件列表 ,以及生成的随机数
- 服务端返回:Server Hello::确认的 TLS 版本号 ,一个随机数 ,确认的密码套件 ,然后Certificate::发送数字证书 ,Server Key Exchange发送选择的椭圆曲线 ,生成随机数作为椭圆曲线的私钥保存本地 ,根据椭圆曲线基点 G 和私钥计算出服务端椭圆曲线公钥,Server Hello Done::打招呼完毕
- 客户端校验证书,如果没问题,生成一个随机数作为客户端椭圆曲线的私钥,发送消息:Client Key Exchange::客户端生成的椭圆曲线公钥 ,Change Cipher Spec::最终的会话密钥,就是用「客户端随机数 + 服务端随机数 + x(ECDHE 算法算出的共享密钥) 」三个材料生成的,告诉服务端后续改用对称算法加密通信,Encrypted Handshake Message::之前发送的数据做一个摘要,再用对称密钥加密一下,让服务端做个验证。
- 服务端发送:Client Key Exchange::服务端生成的椭圆曲线公钥,Encrypted Handshake Message::之前发送的数据做一个摘要,再用对称密钥加密一下,让客户端做个验证
两者区别:
- RSA 密钥协商算法「不支持」前向保密,ECDHE 密钥协商算法「支持」前向保密;
- 使用了 RSA 密钥协商算法,TLS 完成四次握手后,才能进行应用数据传输,而对于 ECDHE 算法,客户端可以不用等服务端的最后一次 TLS 握手,就可以提前发出加密的 HTTP 数据,节省了一个消息的往返时间(这个是 RFC 文档规定的,具体原因文档没有说明,所以这点我也不太明白);
- 使用 ECDHE, 在 TLS 第 2 次握手中,会出现服务器端发出的「Server Key Exchange」消息,而 RSA 握手过程没有该消息;
WebSocket
WebSocket是基于TCP的新协议
建立WebSocket连接
浏览器在 TCP 三次握手 建立连接之后,统一使用 HTTP 协议先进行一次通信。
- 如果这时候是想建立 WebSocket 连接 ,就会在 HTTP 请求里带上一些特殊的header 头 ,包含一段随机生成的 base64 码
makefile
Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2YUyg==\r\n
- 服务器正好支持升级成 WebSocket 协议,根据客户端生成的 base64 码,用某个公开的 算法变成另一段字符串,放在 HTTP 响应的
Sec-WebSocket-Accept
头里,同时带上101状态码
,发回给浏览器,浏览器也用同样的公开算法 将base64码
转成另一段字符串,如果这段字符串跟服务器传回来的字符串一致,那验证通过。
一来一回两次 HTTP 握手,WebSocket就建立完成了,后续双方就可以使用 websocket 的数据格式进行通信了。
长轮询
发起一个请求,在较长时间内等待服务器响应的机制,就是所谓的长轮询机制 ,相比于一般轮询可以减少HTTP请求次数,但还是客户端向服务端请求