CSDNHTTP/3 来了 !HTTP/2 还没怎么用起来呢,先一起扫个盲吧!( 二 )


Step2:服务端生成 g、p、a , 根据 g、p 和 a 算出 A , 然后将 g、p、A 放到 Server Config 中再发送 Rejection 消息给客户端;
Step3:客户端接收到 g、p、A 后 , 自己再生成 b , 根据 g、p、b 算出 B , 根据 A、p、b 算出初始密钥 K 。 B 和 K 算好后 , 客户端会用 K 加密 HTTP 数据 , 连同 B 一起发送给服务端;
Step4:服务端接收到 B 后 , 根据 a、p、B 生成与客户端同样的密钥 , 再用这密钥解密收到的 HTTP 数据 。 为了进一步的安全(前向安全性) , 服务端会更新自己的随机数 a 和公钥 , 再生成新的密钥 S , 然后把公钥通过 Server Hello 发送给客户端 。 连同 Server Hello 消息 , 还有 HTTP 返回数据;
Step5:客户端收到 Server Hello 后 , 生成与服务端一致的新密钥 S , 后面的传输都使用 S 加密 。
这样 , QUIC 从请求连接到正式接发 HTTP 数据一共花了 1 RTT , 这 1 个 RTT 主要是为了获取 Server Config , 后面的连接如果客户端缓存了 Server Config , 那么就可以直接发送 HTTP 数据 , 实现 0 RTT 建立连接 。
CSDNHTTP/3 来了 !HTTP/2 还没怎么用起来呢,先一起扫个盲吧!
本文插图
这里使用的是 DH 密钥交换算法 , DH 算法的核心就是服务端生成 a、g、p 3 个随机数 , a 自己持有 , g 和 p 要传输给客户端 , 而客户端会生成 b 这 1 个随机数 , 通过 DH 算法客户端和服务端可以算出同样的密钥 。 在这过程中 a 和 b 并不参与网络传输 , 安全性大大提高 。 因为 p 和 g 是大数 , 所以即使在网络中传输的 p、g、A、B 都被劫持 , 那么靠现在的计算机算力也没法破解密钥 。
1.4 连接迁移TCP 连接基于四元组(源 IP、源端口、目的 IP、目的端口) , 切换网络时至少会有一个因素发生变化 , 导致连接发生变化 。 当连接发生变化时 , 如果还使用原来的 TCP 连接 , 则会导致连接失败 , 就得等原来的连接超时后重新建立连接 , 所以我们有时候发现切换到一个新网络时 , 即使新网络状况良好 , 但内容还是需要加载很久 。 如果实现得好 , 当检测到网络变化时立刻建立新的 TCP 连接 , 即使这样 , 建立新的连接还是需要几百毫秒的时间 。
QUIC 的连接不受四元组的影响 , 当这四个元素发生变化时 , 原连接依然维持 。 那这是怎么做到的呢?道理很简单 , QUIC 连接不以四元组作为标识 , 而是使用一个 64 位的随机数 , 这个随机数被称为 Connection ID , 即使 IP 或者端口发生变化 , 只要 Connection ID 没有变化 , 那么连接依然可以维持 。
CSDNHTTP/3 来了 !HTTP/2 还没怎么用起来呢,先一起扫个盲吧!
本文插图
1.5 队头阻塞/多路复用HTTP/1.1 和 HTTP/2 都存在队头阻塞问题(Head of line blocking) , 那什么是队头阻塞呢?
TCP 是个面向连接的协议 , 即发送请求后需要收到 ACK 消息 , 以确认对方已接收到数据 。 如果每次请求都要在收到上次请求的 ACK 消息后再请求 , 那么效率无疑很低 。 后来 HTTP/1.1 提出了 Pipelining 技术 , 允许一个 TCP 连接同时发送多个请求 , 这样就大大提升了传输效率 。
CSDNHTTP/3 来了 !HTTP/2 还没怎么用起来呢,先一起扫个盲吧!
本文插图
在这个背景下 , 下面就来谈 HTTP/1.1 的队头阻塞 。 下图中 , 一个 TCP 连接同时传输 10 个请求 , 其中第 1、2、3 个请求已被客户端接收 , 但第 4 个请求丢失 , 那么后面第 5 - 10 个请求都被阻塞 , 需要等第 4 个请求处理完毕才能被处理 , 这样就浪费了带宽资源 。
CSDNHTTP/3 来了 !HTTP/2 还没怎么用起来呢,先一起扫个盲吧!
本文插图
因此 , HTTP 一般又允许每个主机建立 6 个 TCP 连接 , 这样可以更加充分地利用带宽资源 , 但每个连接中队头阻塞的问题还是存在 。


推荐阅读