(四) HTTP/2的流状态

“流”是HTTP/2连接中客户端和服务端之间交换的独立的、双向的帧序列。流具有以下几个重要特性:

流的生命周期和状态转换

流的生命周期如下图所示:

其中,HEADERS帧可以是一个单独的HEADERS帧,也可以是一个HEADERS帧以及紧随它的若干个CONTINUATION帧; 同理,PUSH_PROMISE帧可以是一个单独的PUSH_PROMISE帧,也可以是一个PUSH_PROMISE帧以及紧随它的若干个CONTINUATION帧。

注意,图中只展示了流的状态转换,以及影响流状态转换的帧和标识。在这点上,CONTINUATION帧并不影响流的状态转换,,它们只是前面的HEADERS帧或PUSH_PROMISE帧的有效组成部分。

为了达到状态转换的目的,END_STREAM标识被当做包含它的帧里面的独立事件处理。这样,一个包含END_STREAM标识的HEADERS帧就可能导致两次状态转换。例如,状态是“保留(远程)”的流在接收到一个HEADERS帧后,就会从“保留(远程)”状态转换为“半关闭(本地)”状态,如果HEADERS帧里面包含END_STREAM标识的,流就会继续从“半关闭(本地)”状态转换为“关闭”状态。

当帧在发送途中的时候,每个端点都可能有一个不同的流状态的主观视图。端点之间并不会对流的创建进行协调,每个端点都可以单方面地创建流。状态不匹配的消极后果仅限于发送完RST_STREAM帧之后的“关闭”状态,在这种情况下,端点可能在关闭流之后一段时间仍然收到帧。

流的标识符

流由一个无符号31位整数标识。客户端初始化的流使用奇数标识;服务端初始化的流使用偶数标识。值为0(0x0)的标识被用来标识连接控制消息,因此,不能用来建立新的连接。

升级到HTTP/2的HTTP1.1请求会接收到一个标识值为0x1的流的响应。当升级完成后,对客户端来说,流0x1的状态是“半关闭(本地)”。因此,0x1不能被从HTTP1.1升级的客户端选择为新流的标识。一个新建立的流的标识在数值上必选大于创建端任何已经打开或保留的流的标识。此规则适用于利用HEADERS帧打开的流和利用PUSH_PROMISE帧保留的流。任何端点收到预期之外的流标识时都要响应一个类型是PROTOCOL_ERROR的连接错误。

一个新的流标识被第一次使用时将隐式关闭所有可能已经被对端初始化并且流标识数值小于新标识的处于“空闲”状态的流。例如,如果客户端在流7上发送一个HEADERS帧,在此之前却没有在流5上发送任何帧,那么,当流7的第一个帧被发送或接收时,流5将转换为“关闭”状态。

流标识符不能重复使用。持续时间长的连接可能会导致端点耗尽所有可能的标识值。不能继续建立新的流标识符的客户端可以为后续的新流新建一个新的连接。不能继续建立新的流标识符的服务端可以发送一个GOAWAY帧,从而强制客户端为新的流使用新的连接。

流的并发

端点可以使用SETTINGS帧中的SETTINGS_MAX_CONCURRENT_STREAMS参数来限制并发活跃的流的数量。最大并发流设置是由每个端点具体设置的,并且仅对接收到设置的一端生效。也就是说,由客户端指定服务端所能初始化的流的最大并发数,而由服务端指定客户端所能初始化的流的最大并发数。

处于“打开”状态或任意一种“半关闭”状态的流都被记入端点所初始化的流的数量中。这三种状态的流的计数都受SETTINGS_MAX_CONCURRENT_STREAMS设置的限制。处于任意一种“保留”状态的流不计入流的数量中。

端点打开流的数量不能超出对端设置的值。如果端点接收到HEADERS帧,导致超出它之前公告的最大并发流数量,那么,它必将将此视为一个类型是PROTOCOL_ERROR或REFUSED_STREAM的流错误。对错误码的选择决定了端点是否希望启动自动重试。

如果端点希望将SETTINGS_MAX_CONCURRENT_STREAMS的值减小到低于当前打开的流的数量,那么,它可以关闭超出新值限制的流,也可以让这些流执行完成。

不论你在什么时候结束,重要的是结束之后就不要悔恨

(四) HTTP/2的流状态

相关文章:

你感兴趣的文章:

标签云: