深入 HTTP2(帧,消息,流)
2019-08-17 本文已影响0人
OOM_Killer
http2 协议简介
h2 专注于性能,最大的目标在于用户和网站之间只用一条连接。其h2 的推出并没有改变http1.1 的基本语义。h2的目的是响应复用,头部压缩来提高极致的性能。
其特性在 之前的文章中也做过介绍 https://www.jianshu.com/p/3ea9b33c4678
核心概念
-
连接 Connection
:1个TCP连接包含多个Stream。 -
数据流 Stream
:一个双向通讯数据流,包含1条或多条 message。 -
消息 Message
:对应HTTP/1 中的请求或者响应,包含一个或者多条 Frame -
数据帧
: 最小单位,以二进制压缩格式存放 HTTP/1 中的内容。
http2
一个消息是由 Headers 帧和DATA 帧组成的。
消息的组成
流,消息,帧 之间的关系
流,消息,帧 之间的关系
抓包可以看到 1号 Stream 流 传递了 一个 GET 请求。1号 Stream 流也进行了回复(HEADER+DATA)
http2抓包
在一条 Connection 中,不同的流可以穿插传递,但是同一条流的达到顺序必须是有序的,比如1号流,流内的 帧必须有序。
这就是传输中无序,接收时组装。
帧格式
每个帧标准为9个字节 (可理解为帧头)
帧中指明了其所属于哪一个 Stream流 (Stream Identifier)其占了31 位。
由此可见,一个帧中最重要的就是 Stream Id 了。其余的内容为
-
Length
: 代表整个 frame 的长度,用一个 24 位无符号整数表示 -
Type
: 定义 frame 的类型。帧类型决定了帧主体的格式和语义,如果 type 为 unknown 应该忽略或抛弃。 -
Flags
:是为帧类型相关而预留的布尔标识。标识对于不同的帧类型赋予了不同的语义。 -
R
: 是一个保留的比特位。这个比特的语义没有定义,发送时它必须被设置为 (0x0), 接收时需要忽略。 -
Frame Payload
: 是主体内容,由帧类型决定
下图为wireshark中抓取的帧,上述的帧格式可以对比找到
wireshark中的帧
正是将每一个帧关联到流上。才实现了多路复用。这个多路复用指的是很多个流之间的帧随意穿插。比如客户端收到 1流的 1 帧,又收到了 2流的3帧,再收到了3流的4帧,1流的2帧,1流的3帧,3流的5帧。
注意。相同的流之内,其帧必须是按顺序的。
看一下下面的图。还是之前的抓包图
http2抓包
有没有发现除了 0 帧之外,为什么没有偶数帧?1,3,5 。。。
这就是因为 由客户端发起的连接,必须是奇数流。服务端发起的必须是偶数流
一般服务端推送算作是服务端发起的连接,也就会出现偶数流了。
要想实现并发,其实就是建立多个流。因为单个流因为必须顺序发送,所以没有办法做到并发。
- 流状态管理的约束性规定
- 新建立的流ID必须大于曾经建立过状态为opened 或者 reserved 的流ID。
- 在新建立的流ID发送帧时,意味着更小ID为idle的流就必须置为closed了。
- Stream ID 不能复用,长连接耗尽的ID,只能通过重新建立TCP连接了。
Stream ID 为 0 的帧 是 控制帧,如setting,window_update,ping等帧。