读http协议2.0
最早期的 HTTP/1.0 时代,一个资源 = 一个 TCP 链接 = 一个 HTTP 链接,每个 HTTP 请求结束都会断开 TCP 连接,新的 HTTP 请求会另外新建一个 TCP 连接,并且只有当一个完整的请求结束(TCP closed)才会开始下一个请求(阻塞)。
(为每一个资源所付出的握手挥手开销在现在的时代是无法容忍的)
这种使用 TCP 的方式最严重的问题是阻塞。后来为了解决阻塞问题,请求允许并发,即同一个域名允许建立多个 TCP 链接,这样算是解决了部分阻塞问题,然后为了解决 TCP 连接利用率低的问题,所以又提出了长链接。
(set HTTP Header Connection: keep-alive
)
端口和TCP的关系参见:https://blog.csdn.net/weixin_40710708/article/details/116795880
但是还是有线头阻塞(Head of line blocking)的问题,即一个 TCP 连接一次只能发出一个请求,所以客户端必须等待收到响应后才能发出另外一个请求,这样耗时的请求如果在前面会 block 后面耗时的请求。
(想想在RPC框架内使用http,这样几乎是不可接受的。然而grpc使用http2.0已经成为RPC协议的一个模板。trpc相当程度的借鉴了grpc,作为c++大厂使用TCP也是意料之中框架性能可以不用不能没有)
线头阻塞问题参见:https://www.zhihu.com/question/420898727/answer/1471214946
http2.0抽象描述:在客户端与服务器之间仅建立一个 TCP 连接,而且该连接在交互持续期间一直处于打开状态。在此连接上,消息是通过逻辑流进行传递的。一条消息包含一个完整的帧序列。在经过整理后,这些帧表示一个响应或请求。
- Connection (连接):仅与一个对等节点建立一个
- Stream(流):逻辑意义上的流,物理实体为连接,一个物理连接拥有多个逻辑流
- 消息 Message(请求/响应):是一组帧,通过逻辑流传输,重建这些帧会得到一个完整的请求或者响应
- 帧(Frame):通信的基本单位
HTTP/2.0 文本格式跟二进制格式的主要差别在于解析
- 比如 TCP 就是二进制协议,每一位表示什么都是固定的,解析起来只用判断 0/1 就好,效率更高
- HTTP/1.0 就是文本协议,因为都是字符串,解析起来要么是正则,要么是状态机,效率更低(正则解析就不是状态机了??)
多路复用就是将消息分成更小的单位(帧),这样就实现了完全双向的请求和响应消息复用。(划分逻辑流)
优点:
- Request 和 Response 都在一个 socket
- 所有的响应和请求都无法相互阻塞
- 减少了建立连接带来的延迟
- 不再需要像 HTTP/1.1 那样将多个请求合成一个
(缺点,HTTP2.0底层还是TCP,用TCP就会有缓冲区,如果一个http请求返回的content特别大,将缓冲区占满你还是会阻塞)
服务器推送允许服务器预测客户端的需要,在请求处理完成之前就可以先发一个 PUSH_PROMISE frame,然后在 push 资源。为防止发送不必要的资源,服务器会给每一个要推送的资源发送一个 PUSH_PROMISE frame,如果资源已经有缓存,浏览器可以 respond 一个 RST_STREAM frame,来拒绝 PUSH。
(好处在于无需等待浏览器解析html,再向服务器请求前端资源,等于少了一个http来回的时间)
流控制
(字面义,允许客户端通知服务端滑动窗口的大小,在视频流服务中有用)
头部压缩(缓存)
使用 HPACK 协议,要求客户端和服务器各自维护一个 HEADER 字段的列表,在多次发送的时候,只发送差异的部分,其余的从缓存表里面取。
传输优先级
Messgae 通过流传输,每个流都会被指定一个优先级,优先级决定处理的顺序和分配的资源,优先级的大小会在 HEADER frame 或者是 PRIORITY frame,为 0 - 256 的数字,优先级还可以为树形结构,来标记依赖关系。
(比如访问网页优先传输文本、js和css,然后再传输图片渲染,提升用户体验)