後追いながら、HTTP2の勉強をしてます。
少しずつ理解できてきたような気がする。
間違っていたら詳しい方はご指摘ください。
ストリーム状態遷移
ストリームには状態があり、送信できるフレームと送信できないフレームがある。
+--------+
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 |
`---------------------->| |<----------------------'
+--------+
H: HEADERS フレーム (CONTINUATION が続く可能性がある)
PP: PUSH_PROMISE フレーム (CONTINUATION が続く可能性がある)
ES: END_STREAM フラグ
R: RST_STREAM フレーム
自分の理解のために表にしてみた。
HEADERSを送信できる状態は、その後にCONTINUATIONもDATAも送信できるものとする。
ストリーム状態 | 送信可能 | 遷移する状態 | 受信可能 |
---|---|---|---|
idle | HEADERS PUSH_PROMISE(予約ID) |
open reserved (local) reserved (remote) |
HEADERS PRIORITY |
reserved (local) | HEADERS RST_STREAM PRIORITY |
half closed (remote) closed |
RST_STREAM PRIORITY WINDOW_UPDATE |
reserved (remote) | RST_STREAM PRIORITY WINDOW_UPDATE |
half closed (local) closed |
HEADERS RST_STREAM PRIORITY |
open | HEADERS(END_STREAM) RST_STREAM |
half closed (local) half closed (remote) closed |
PUSH_PROMISE以外 |
half closed (local) | RST_STREAM PRIORITY WINDOW_UPDATE |
closed | 全て可能 |
half closed (remote) | HEADERS(END_STREAM) RST_STREAM |
closed | RST_STREAM PRIORITY WINDOW_UPDATE |
closed | PRIORITY | reserved | WINDOW_UPDATE(加算する必要あり) |
half closedとはなにか
ある開いたストリームがclosed状態になるには3つのパターンがある。
- GETに対するレスポンスなど、双方でデータの送受信を行う場合はEND_STREAMの送信と受信
- 片方からだけプッシュする場合は、データ送信者のEND_STREAMの送信
- RST_STREAMの送信か受信
half closedは、片方がそれ以上DATAを送信しない状態。(という理解で合ってると思う)
ドラフトの図を見るとhalf closedには二つある。
- half closed (remote)
- half closed (local)
remoteは、自分から見て現在のIDのストリームの相手の状態。
localは、自分から見て現在のIDのストリームの状態。
#half closed(remote)
自分は何かを送るが、相手がそれ以上DATAを送らない状態。つまり相手からEND_STREAMを受けた状態。
図の左側は自分からPUSHしてるので、相手は受信するだけなのでこの状態になっている。相手はこれ以上送信してこないので、残りの作業は自分が送りたいものを送りきってEND_STREAMを送信すること。
これは相手が「GET /」を送ってきた後の状態に等しい。(たぶん)
サーバープッシュの場合はPUSH_PROMISEで予約が終わって、これから送りたいものを送る前の状態。
#half closed(local)
自分はこれ以上DATAを送らない状態。つまり自分からEND_STREAMを送った状態。
残りの作業は相手から送られてくる様々なフレームを受信して、END_STREAMが来るまで待つ事。だから表では「全て受信可能」になっている。
これは自分が「GET /」を送った後の状態に等しい。はず。。
サーバープッシュの場合はPUSH_PROMISEで通知を受けて、これからDATAが降ってくるのを待っている状態。
#END_STREAMフラグとRST_STREAM
なぜストリームを終了させるのにEND_STREAMフラグとRST_STREAMがあるのか?
RST_STREAMはキャンセルやエラー処理のための即断を意味するので、基本的にはEND_STREAMフラグで終了させるのが正しい。たぶん。