RFC9000中文文档 StreamState

3.Stream States

本节根据其发送或接收组件描述流。 描述了两种状态机:一个用于端点传输数据的流(第 3.1 节),另一个用于端点接收数据的流(第 3.2 节)。

单向流使用发送或接收状态机,具体取决于流类型和端点角色。 双向流在两个端点都使用两个状态机。 在大多数情况下,无论流是单向的还是双向的,这些状态机的使用都是相同的。 对于双向流,打开流的条件稍微复杂一些,因为打开发送端或接收端都会导致流双向打开。

本节中显示的状态机提供了大量信息。 本文档使用流状态来描述何时以及如何发送不同类型的帧的规则,以及在接收到不同类型的帧时预期的反应。 尽管这些状态机旨在用于实现 QUIC,但这些状态并非旨在约束实现。 只要其行为与实现这些状态的实现一致,实现就可以定义不同的状态机。

Notes:在某些情况下,单个事件或操作可能会导致通过多个状态进行转换。 例如,发送设置了 FIN 位的 STREAM 会导致发送流的两种状态转换:从“Ready”状态到“Send”状态,以及从“Send”状态到“Data Sent”状态

3.1 发送流状态

图 2 显示了将数据发送到对等点的部分流的状态。

image-20220217202657746

端点启动的流的发送部分(类型 0 和 2 用于客户端,1 和 3 用于服务器)由应用程序打开。 “就绪”状态表示新创建的流,它能够接受来自应用程序的数据。 流数据可能会在此状态下缓冲以准备发送。

发送第一个 STREAM 或 STREAM_DATA_BLOCKED 帧会导致流的发送部分进入“发送”状态。 实现可能会选择推迟将流 ID 分配给流,直到它发送第一个 STREAM 帧并进入此状态,这可以允许更好的流优先级。

由对等方发起的双向流的发送部分(类型 0 用于服务器,类型 1 用于客户端)在创建接收部分时以“就绪”状态开始

在“Send”状态下,端点以 STREAM 帧传输——并在必要时重新传输——流数据。端点尊重其对等方设置的流量控制限制,并继续接受和处理 MAX_STREAM_DATA 帧。如果端点被流控制限制(第 4.1 节)阻止发送,则处于“发送”状态的端点会生成 STREAM_DATA_BLOCKED 帧。

在应用程序指示所有流数据已发送完毕并发送一个包含 FIN 位的 STREAM 帧后,流的发送部分进入“Data Sent”状态。 从这个状态开始,端点只在必要时重新传输流数据。 端点不需要检查流控制限制或为处于此状态的流发送 STREAM_DATA_BLOCKED 帧。 可能会收到 MAX_STREAM_DATA 帧,直到对等方收到最终的流偏移量。 端点可以安全地忽略它从其对等方接收到的任何 MAX_STREAM_DATA 帧以获取处于此状态的流。

一旦所有流数据都被成功确认,流的发送部分进入“Data Recvd”状态,这是一个终端状态

从“Ready”、“Send”或“Data Sent”之一的任何状态,应用程序都可以发出信号,表示它希望放弃流数据的传输。 或者,端点可能会从其对等端接收到 STOP_SENDING 帧。 在任何一种情况下,端点都会发送一个 RESET_STREAM 帧,这会导致流进入“Reset Sent”状态。

端点可以发送 RESET_STREAM 作为提及流的第一帧; 这会导致该流的发送部分打开,然后立即转换到“重置发送”状态。

一旦确认了包含 RESET_STREAM 的数据包,流的发送部分将进入“Reset Recvd”状态,这是一个终端状态。

3.2 接收流状态

图 3 显示了从对等点接收数据的部分流的状态。 流的接收部分的状态仅反映对等点的流的发送部分的一些状态。 流的接收部分不会跟踪发送部分上无法观察到的状态,例如“就绪”状态。 相反,流的接收部分会跟踪数据向应用程序的传递,其中一些数据不能被发送者观察到。

image-20220217204057182

当接收到该流的第一个 STREAM、STREAM_DATA_BLOCKED 或 RESET_STREAM 帧时,将创建由对等点启动的流的接收部分(客户端的类型 1 和 3,或服务器的类型 0 和 2)。对于由对等方发起的双向流,接收流的发送部分的 MAX_STREAM_DATA 或 STOP_SENDING 帧也会创建接收部分。流的接收部分的初始状态是“Recv”。

对于双向流,当端点发起的发送部分(客户端类型0,服务器类型1)进入“Ready”状态时,接收部分进入“Recv”状态。

当从对等方接收到该流的 MAX_STREAM_DATA 或 STOP_SENDING 帧时,端点打开双向流。接收到未打开流的 MAX_STREAM_DATA 帧表示远程对等方已打开流并正在提供流控制信用。接收到未打开流的 STOP_SENDING 帧表明远程对等方不再希望接收此流上的数据。如果数据包丢失或重新排序,任一帧都可能在 STREAM 或 STREAM_DATA_BLOCKED 帧之前到达。

在创建流之前,具有较小流 ID 的相同类型的所有流必须倍创建。 这确保了流的创建顺序在两个端点上是一致的。

在“Recv”状态,端点接收 STREAM 和 STREAM_DATA_BLOCKED 帧。 传入的数据被缓冲,并且可以重新组合成正确的顺序以交付给应用程序。 随着应用程序消耗数据并且缓冲区空间变得可用,端点发送 MAX_STREAM_DATA 帧以允许对等方发送更多数据。

当接收到带有 FIN 位的 STREAM 帧时,流的最终大小是已知的; 见第 4.5 节。 流的接收部分然后进入“大小已知”状态。 在这种状态下,端点不再需要发送 MAX_STREAM_DATA 帧; 它只接收流数据的任何重传

一旦接收到流的所有数据,接收部分就进入“Data Recvd”状态。 这可能是由于接收到导致转换为“已知大小”的相同 STREAM 帧的结果。 接收到所有数据后,可以丢弃流的任何 STREAM 或 STREAM_DATA_BLOCKED 帧。

“Data Recvd”状态一直持续到流数据已交付给应用程序。 一旦传输了流数据,流就进入“数据读取”状态,这是一个终端状态。

在“Recv”或“Size Known”状态下接收 RESET_STREAM 帧会导致流进入“Reset Recvd”状态。 这可能会导致流数据到应用程序的传输被中断。

当接收到 RESET_STREAM 时(即处于“Data Recvd”状态),可能已经接收到所有流数据。 类似地,剩余的流数据有可能在接收到 RESET_STREAM 帧后到达(“Reset Recvd”状态)。 实现可以根据自己的选择自由地管理这种情况。

发送 RESET_STREAM 意味着端点不能保证流数据的传递; 但是,如果接收到 RESET_STREAM,则不要求不传送流数据。 实现可能会中断流数据的传递,丢弃任何未使用的数据,并发出接收到 RESET_STREAM 的信号。 如果流数据被完全接收并被缓冲以供应用程序读取,则可能会抑制或保留 RESET_STREAM 信号。 如果 RESET_STREAM 被抑制,则流的接收部分保持在“Data Recvd”中。

一旦应用程序接收到指示流被重置的信号,流的接收部分就会转换到“Reset Read”状态,这是一个终端状态。

3.3 允许的帧类型

流的发送方仅发送三种影响发送方或接收方的流状态的帧类型:STREAM(第 19.8 节)、STREAM_DATA_BLOCKED(第 19.13 节)和 RESET_STREAM(第 19.4 节)。

发送方必须从终端状态(“Data Recvd”或“Reset Recvd”)发送这些帧中的任何一个。 发送方不得为处于“Reset Sent”状态或任何终端状态的流发送 STREAM 或 STREAM_DATA_BLOCKED 帧——即在发送 RESET_STREAM 帧之后。 接收器可以在任何状态下接收这三个帧中的任何一个,因为可能会延迟传送携带它们的数据包。

流的接收者发送 MAX_STREAM_DATA 帧(第 19.10 节)和 STOP_SENDING 帧(第 19.5 节)

接收方仅在“Recv”状态下发送 MAX_STREAM_DATA 帧。 接收器可以在它没有收到 RESET_STREAM 帧的任何状态下发送 STOP_SENDING 帧——即,除了“Reset Recvd”或“Reset Read”之外的状态。 但是,在“Data Recvd”状态下发送 STOP_SENDING 帧没有什么价值,因为所有流数据都已接收。 由于数据包的延迟传递,发送方可以在任何状态下接收这两种类型的帧中的任何一种

3.4 双向流状态

双向流由发送和接收部分组成。 实现可以将双向流的状态表示为发送和接收流状态的组合。 最简单的模型在发送或接收部分都处于非终端状态时将流表示为“打开”,当发送和接收流都处于终端状态时将流表示为“关闭”。

表 2 显示了与 HTTP/2[HTTP2] 中定义的流状态松散对应的双向流状态的更复杂映射。这表明发送或接收部分流的多个状态映射到相同的复合状态。 请注意,这只是这种映射的一种可能性; 此映射要求在转换到“关闭”或“半关闭”状态之前确认数据.

Sending Part Sending Part Composite State
No Stream / Ready No Stream / Recv (*1) idle
Ready / Send / Data Sent Recv / Size Known open
Ready / Send / Data Sent Data Recvd / Data Read half-closed (remote)
Ready / Send / Data Sent Reset Recvd / Reset Read half-closed (remote)
Data Recvd Recv / Size Known half-closed (local)
Reset Sent / Reset Recvd Recv / Size Known half-closed (local)
Reset Sent / Reset Recvd Data Recvd / Data Read closed
Reset Sent / Reset Recvd Reset Recvd / Reset Read closed
Data Recvd Data Recvd / Data Read closed
Data Recvd Reset Recvd / Reset Read closed

Table 2: Possible Mapping of Stream States to HTTP/2

3.5. 请求状态转换

如果应用程序不再对它在流上接收的数据感兴趣,它可以中止读取流并指定应用程序错误代码。

如果流处于“Recv”或“已知大小”状态,则传输应通过发送 STOP_SENDING 帧来提示此情况,以提示在相反方向关闭流。 这通常表明接收应用程序不再读取它从流中接收到的数据,但这并不能保证传入的数据将被忽略

发送 STOP_SENDING 帧后收到的 STREAM 帧仍计入连接和流流控制,即使这些帧在收到时可以丢弃。

STOP_SENDING 帧请求接收端点发送 RESET_STREAM 帧。 一个接收 STOP_SENDING 帧的端点如果流必须发送 RESET_STREAM 帧处于“就绪”或“发送”状态。 如果流处于“数据已发送”状态,端点可能会延迟发送 RESET_STREAM 帧,直到包含未完成数据的数据包承认或宣布丢失。 如果任何未完成的数据被宣布丢失,端点应该发送 RESET_STREAM 帧而不是重新传输数据

端点应该将错误代码从 STOP_SENDING 帧复制到它发送的 RESET_STREAM 帧,但它可以使用任何应用程序错误代码。 发送 STOP_SENDING 帧的端点可能会忽略随后为该流接收的任何 RESET_STREAM 帧中的错误代码。

STOP_SENDING 应该只为尚未被对等方重置的流发送。 STOP_SENDING 对于处于“Recv”或“Size Known”状态的流最有用。

如果包含先前 STOP_SENDING 的数据包丢失,则端点应发送另一个 STOP_SENDING 帧。 但是,一旦为流接收到所有流数据或 RESET_STREAM 帧——也就是说,流处于“Recv”或“已知大小”以外的任何状态——就不需要发送 STOP_SENDING 帧。 希望终止双向流的两个方向的端点可以通过发送 RESET_STREAM 帧来终止一个方向,并且可以通过发送 STOP_SENDING 帧来鼓励在相反方向上立即终止。

posted @ 2022-02-18 22:51  li33的博客  阅读(686)  评论(0编辑  收藏  举报