メインコンテンツまでスキップ

3. ストリーム状態

3. ストリーム状態

このセクションでは、ストリームを送信コンポーネントまたは受信コンポーネントの観点から説明します。2つの状態機械が説明されています: エンドポイントがデータを送信するストリーム用の状態機械 (セクション 3.1) と、エンドポイントがデータを受信するストリーム用の状態機械 (セクション 3.2) です。

単方向ストリームは、ストリームタイプとエンドポイントの役割に応じて、送信状態機械または受信状態機械のいずれかを使用します。双方向ストリームは、両方のエンドポイントで両方の状態機械を使用します。ほとんどの場合、ストリームが単方向か双方向かに関係なく、これらの状態機械の使用は同じです。双方向ストリームのストリームを開く条件は、送信側または受信側のいずれかを開くとストリームが両方向で開かれるため、わずかに複雑です。

このセクションに示されている状態機械は主に情報提供です。このドキュメントでは、ストリーム状態を使用して、異なるタイプのフレームをいつどのように送信できるか、および異なるタイプのフレームが受信されたときに期待される反応に関するルールを説明します。これらの状態機械はQUICの実装に役立つことを意図していますが、これらの状態は実装を制約することを意図していません。実装は、これらの状態を実装する実装と動作が一致している限り、異なる状態機械を定義できます。

注記

場合によっては、単一のイベントまたはアクションが複数の状態を通じて遷移を引き起こす可能性があります。たとえば、FINビットが設定されたSTREAMを送信すると、送信ストリームに対して2つの状態遷移が発生する可能性があります:「Ready」状態から「Send」状態へ、および「Send」状態から「Data Sent」状態へ。

3.1 送信ストリーム状態

図 2 は、ピアにデータを送信するストリームの部分の状態を示しています。

       o
| Create Stream (Sending)
| Peer Creates Bidirectional Stream
v
+-------+
| Ready | Send RESET_STREAM
| |-----------------------.
+-------+ |
| |
| Send STREAM / |
| STREAM_DATA_BLOCKED |
v |
+-------+ |
| Send | Send RESET_STREAM |
| |---------------------->|
+-------+ |
| |
| Send STREAM + FIN |
v v
+-------+ +-------+
| Data | Send RESET_STREAM | Reset |
| Sent |------------------>| Sent |
+-------+ +-------+
| |
| Recv All ACKs | Recv ACK
v v
+-------+ +-------+
| Data | | Reset |
| Recvd | | Recvd |
+-------+ +-------+

図 2: ストリームの送信部分の状態

エンドポイントが開始するストリーム (クライアントの場合はタイプ 0 および 2、サーバーの場合は 1 および 3) の送信部分は、アプリケーションによって開かれます。「Ready」状態は、アプリケーションからデータを受け入れることができる新しく作成されたストリームを表します。ストリームデータは、送信の準備としてこの状態でバッファリングされる可能性があります。

最初のSTREAMまたはSTREAM_DATA_BLOCKEDフレームを送信すると、ストリームの送信部分が「Send」状態に入ります。実装は、最初のSTREAMフレームを送信してこの状態に入るまで、ストリームへのストリームIDの割り当てを延期することを選択できます。これにより、より良いストリームの優先順位付けが可能になります。

ピアによって開始された双方向ストリーム (サーバーの場合はタイプ 0、クライアントの場合はタイプ 1) の送信部分は、受信部分が作成されると「Ready」状態で開始します。

「Send」状態では、エンドポイントはSTREAMフレームでストリームデータを送信し、必要に応じて再送信します。エンドポイントは、ピアによって設定されたフロー制御制限を尊重し、MAX_STREAM_DATAフレームを受け入れて処理し続けます。「Send」状態のエンドポイントは、ストリームフロー制御制限によって送信がブロックされている場合、STREAM_DATA_BLOCKEDフレームを生成します (セクション 4.1)。

アプリケーションがすべてのストリームデータが送信されたことを示し、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を送信することができます (MAY); これにより、そのストリームの送信部分が開かれ、その後すぐに「Reset Sent」状態に遷移します。

RESET_STREAMを含むパケットが確認応答されると、ストリームの送信部分は終端状態である「Reset Recvd」状態に入ります。

3.2 受信ストリーム状態

図 3 は、ピアからデータを受信するストリームの部分の状態を示しています。ストリームの受信部分の状態は、ピアのストリームの送信部分の状態の一部のみを反映しています。ストリームの受信部分は、「Ready」状態など、観察できない送信部分の状態を追跡しません。代わりに、ストリームの受信部分は、アプリケーションへのデータの配信を追跡し、その一部は送信者によって観察できません。

       o
| Recv STREAM / STREAM_DATA_BLOCKED / RESET_STREAM
| Create Bidirectional Stream (Sending)
| Recv MAX_STREAM_DATA / STOP_SENDING (Bidirectional)
| Create Higher-Numbered Stream
v
+-------+
| Recv | Recv RESET_STREAM
| |-----------------------.
+-------+ |
| |
| Recv STREAM + FIN |
v |
+-------+ |
| Size | Recv RESET_STREAM |
| Known |---------------------->|
+-------+ |
| |
| Recv All Data |
v v
+-------+ Recv RESET_STREAM +-------+
| Data |--- (optional) --->| Reset |
| Recvd | Recv All Data | Recvd |
+-------+<-- (optional) ----+-------+
| |
| App Read All Data | App Read Reset
v v
+-------+ +-------+
| Data | | Reset |
| Read | | Read |
+-------+ +-------+

図 3: ストリームの受信部分の状態

ピアによって開始されたストリーム (クライアントの場合はタイプ 1 および 3、またはサーバーの場合は 0 および 2) の受信部分は、そのストリームに対する最初のSTREAM、STREAM_DATA_BLOCKED、またはRESET_STREAMフレームが受信されたときに作成されます。ピアによって開始された双方向ストリームの場合、ストリームの送信部分に対する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を持つ同じタイプのすべてのストリームが作成されなければなりません (MUST)。これにより、両方のエンドポイントでストリームの作成順序が一貫していることが保証されます。

「Recv」状態では、エンドポイントはSTREAMおよびSTREAM_DATA_BLOCKEDフレームを受信します。着信データはバッファリングされ、アプリケーションへの配信のために正しい順序で再組み立てできます。データがアプリケーションによって消費され、バッファスペースが利用可能になると、エンドポイントはMAX_STREAM_DATAフレームを送信して、ピアがより多くのデータを送信できるようにします。

FINビットを持つSTREAMフレームが受信されると、ストリームの最終サイズがわかります; セクション 4.5 を参照してください。その後、ストリームの受信部分は「Size Known」状態に入ります。この状態では、エンドポイントはMAX_STREAM_DATAフレームを送信する必要がなくなります; ストリームデータの再送信のみを受信します。

ストリームのすべてのデータが受信されると、受信部分は「Data Recvd」状態に入ります。これは、「Size Known」への遷移を引き起こすのと同じSTREAMフレームの受信の結果として発生する可能性があります。すべてのデータが受信された後、ストリームのSTREAMまたはSTREAM_DATA_BLOCKEDフレームは破棄できます。

「Data Recvd」状態は、ストリームデータがアプリケーションに配信されるまで持続します。ストリームデータが配信されると、ストリームは終端状態である「Data Read」状態に入ります。

「Recv」または「Size Known」状態でRESET_STREAMフレームを受信すると、ストリームは「Reset Recvd」状態に入ります。これにより、アプリケーションへのストリームデータの配信が中断される可能性があります。

RESET_STREAMが受信されたとき (つまり、「Data Recvd」状態)、すべてのストリームデータがすでに受信されている可能性があります。同様に、RESET_STREAMフレームを受信した後に残りのストリームデータが到着する可能性があります (「Reset Recvd」状態)。実装は、この状況を選択した方法で管理することができます。

RESET_STREAMを送信することは、エンドポイントがストリームデータの配信を保証できないことを意味します; ただし、RESET_STREAMが受信された場合にストリームデータが配信されないという要件はありません。実装は、ストリームデータの配信を中断し、消費されなかったデータを破棄し、RESET_STREAMの受信を通知することができます (MAY)。ストリームデータが完全に受信され、アプリケーションによって読み取られるためにバッファリングされている場合、RESET_STREAM信号は抑制または保留される可能性があります。RESET_STREAMが抑制された場合、ストリームの受信部分は「Data Recvd」に残ります。

アプリケーションがストリームがリセットされたことを示す信号を受信すると、ストリームの受信部分は終端状態である「Reset Read」状態に遷移します。

3.3 許可されたフレームタイプ

ストリームの送信者は、送信者または受信者のいずれかでストリームの状態に影響を与える3つのフレームタイプのみを送信します: STREAM (セクション 19.8)、STREAM_DATA_BLOCKED (セクション 19.13)、およびRESET_STREAM (セクション 19.4)。

送信者は、終端状態 (「Data Recvd」または「Reset Recvd」) からこれらのフレームのいずれも送信してはなりません (MUST NOT)。送信者は、「Reset Sent」状態または任意の終端状態のストリームに対して、STREAMまたはSTREAM_DATA_BLOCKEDフレームを送信してはなりません (MUST NOT) -- つまり、RESET_STREAMフレームを送信した後です。受信者は、それらを運ぶパケットの遅延配信の可能性があるため、任意の状態でこれら3つのフレームのいずれかを受信する可能性があります。後の状態でのフレームの受信は、エラーとして扱ってはならず (MUST NOT)、送信部分の状態を変更しません。

受信者は、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] のストリーム状態にほぼ対応する、より複雑な双方向ストリーム状態のマッピングを示しています。これは、ストリームの送信部分または受信部分の複数の状態が同じ複合状態にマップされることを示しています。これは、そのようなマッピングの1つの可能性にすぎないことに注意してください; このマッピングでは、「クローズ」または「ハーフクローズ」状態に遷移する前にデータが確認応答される必要があります。

送信部分受信部分複合状態
No Stream/ReadyNo Stream/Recv *1idle
Ready/Send/Data SentRecv/Size Knownopen
Ready/Send/Data SentData Recvd/Data Readhalf-closed (remote)
Ready/Send/Data SentReset Recvd/Reset Readhalf-closed (remote)
Data RecvdRecv/Size Knownhalf-closed (local)
Reset Sent/Reset RecvdRecv/Size Knownhalf-closed (local)
Reset Sent/Reset RecvdData Recvd/Data Readclosed
Reset Sent/Reset RecvdReset Recvd/Reset Readclosed
Data RecvdData Recvd/Data Readclosed
Data RecvdReset Recvd/Reset Readclosed

表 2: HTTP/2へのストリーム状態のマッピングの可能性

*1

「No Stream」状態は仮説的なものであることに注意してください; エンドポイントもそのピアもストリームを作成していません。

3.5 要請された状態遷移

アプリケーションがストリーム上で受信しているデータにもはや関心がない場合、ストリームの読み取りを中止し、アプリケーションエラーコードを指定できます。

ストリームが「Recv」または「Size Known」状態にある場合、トランスポートは、STOP_SENDINGフレームを送信して反対方向でのストリームのクローズを促すことで、これを通知すべきです (SHOULD)。これは通常、受信アプリケーションがストリームから受信するデータを読み取らなくなったことを示しますが、着信データが無視されることを保証するものではありません。

STOP_SENDINGフレームを送信した後に受信されたSTREAMフレームは、これらのフレームが受信時に破棄される可能性があるにもかかわらず、接続およびストリームフロー制御にカウントされます。

STOP_SENDINGフレームは、受信エンドポイントがRESET_STREAMフレームを送信することを要求します。STOP_SENDINGフレームを受信したエンドポイントは、ストリームが「Ready」または「Send」状態にある場合、RESET_STREAMフレームを送信しなければなりません (MUST)。ストリームが「Data Sent」状態にある場合、エンドポイントは、未処理のデータを含むパケットが確認応答されるか損失として宣言されるまで、RESET_STREAMフレームの送信を延期することができます (MAY)。未処理のデータが損失として宣言された場合、エンドポイントはデータを再送信する代わりにRESET_STREAMフレームを送信すべきです (SHOULD)。

エンドポイントは、STOP_SENDINGフレームからエラーコードを送信するRESET_STREAMフレームにコピーすべきですが (SHOULD)、任意のアプリケーションエラーコードを使用できます。STOP_SENDINGフレームを送信するエンドポイントは、そのストリームに対してその後受信されるRESET_STREAMフレーム内のエラーコードを無視することができます (MAY)。

STOP_SENDINGは、ピアによってリセットされていないストリームに対してのみ送信すべきです (SHOULD)。STOP_SENDINGは、「Recv」または「Size Known」状態のストリームに最も有用です。

前のSTOP_SENDINGを含むパケットが失われた場合、エンドポイントは別のSTOP_SENDINGフレームを送信することが期待されます。ただし、ストリームのすべてのストリームデータまたはRESET_STREAMフレームのいずれかが受信されると -- つまり、ストリームが「Recv」または「Size Known」以外の任意の状態にある場合 -- STOP_SENDINGフレームの送信は不要です。

双方向ストリームの両方向を終了したいエンドポイントは、RESET_STREAMフレームを送信して一方向を終了でき、STOP_SENDINGフレームを送信して反対方向での迅速な終了を促すことができます。