为什么一个流收到了END_STREAM标志位之后还可以继续接收数据帧(详解HTTP/2 stream的状态变化)

首先附上答案:
在wireshark抓包的时候,发现一个data帧包含了END_STREAM标志位,可这个流却依然没有结束,仍在继续传输数据帧 —— 这是因为流的状态从open变成了half_closed(local),在这个状态下,流只可以发送Window_Updata,Priority,RST_Stream帧,可以接收任意帧。

frame中帧的标志位(flags)

一个frame是HTTP/2通信中最小的数据传输单元,frame的定义如下:

+-----------------------------------------------+
|                 Length (24)                   |
+---------------+---------------+---------------+
|   Type (8)    |   Flags (8)   |
+-+-------------+---------------+-------------------------------+
|R|                 Stream Identifier (31)                      |
+=+=============================================================+
|                   Frame Payload (0...)                      ...
+---------------------------------------------------------------+

其中Flags为帧的标志位,如END_HEADERS为0x04(标志着头部数据的结束),END_STREAM为0x01(标志着流的结束)。

附上stream的简单转换过程
Stream的状态转换

                             +--------+
                     send PP |        | recv PP
                    ,--------|  idle  |--------.
                   /         |        |         \
                  v          +--------+          v
           +----------+          |           +----------+
           |          |          | send H /  |          |
    ,------| reserved |          | recv H    | reserved |------.
    |      | (local)  |          |           | (remote) |      |
    |      +----------+          v           +----------+      |
    |          |             +--------+             |          |
    |          |     recv ES |        | send ES     |          |
    |   send H |     ,-------|  open  |-------.     | recv H   |
    |          |    /        |        |        \    |          |
    |          v   v         +--------+         v   v          |
    |      +----------+          |           +----------+      |
    |      |   half   |          |           |   half   |      |
    |      |  closed  |          | send R /  |  closed  |      |
    |      | (remote) |          | recv R    | (local)  |      |
    |      +----------+          |           +----------+      |
    |           |                |                 |           |
    |           | send ES /      |       recv ES / |           |
    |           | send R /       v        send R / |           |
    |           | recv R     +--------+   recv R   |           |
    | send R /  `----------->|        |<-----------'  send R / |
    | recv R                 | closed |               recv R   |
    `----------------------->|        |<----------------------'
                             +--------+
       send:   endpoint sends this frame
       recv:   endpoint receives this frame
       H:  HEADERS frame (with implied CONTINUATIONs)
       PP: PUSH_PROMISE frame (with implied CONTINUATIONs)
       ES: END_STREAM flag
       R:  RST_STREAM frame

half closed (local/remote)
half closed (local/remote)
状态half closed (local)与half closed (remote)中的local与remote的区别,完全是基于各端自己的视角。对于同一个流的两端,如果一端认为这个流的状态是half closed (local),那么另一端只能认为这个流的状态是half closed (remote)。
处于half closed (local)状态的流只能被用于发送WINDOW_UPDATE,PRIORITY和RST_STREAM帧,但可以被用于接收任何类型的帧。相对应地,处于half closed (remote)状态的流只能被用于接收WINDOW_UPDATE,PRIORITY和RST_STREAM帧,但可以被用于发送任何类型的帧。

猜你喜欢

转载自blog.csdn.net/weixin_45022086/article/details/108750765