[122] WebSocketクライアントは close
メソッドによって接続を閉じることができます。 WebSocket接続を閉じる際は
Close
フレームによる closing handshake が行われます。
[123] その他に、 Close
フレームを使わない異常終了処理も規定されています。
[44] WebSocket接続の終了は、次のような動作により開始されます。
[128] 接続を閉じる動作の大まかな流れは次のようになります。
[37] クライアントは、トランスポート層の接続が失われたら、 WebSocket接続失敗を実行しなければなりません >>12。
[36] クライアントは、応用から指示された場合やプロトコルで規定されている場合を除き、 接続を閉じるべきではありません >>12。 閉じる場合は、 Start the WebSocket Closing Handshake を実行します >>12。
[40] サーバーは、適宜接続を閉じて構いません >>12。 閉じる場合は、 Start the WebSocket Closing Handshake を実行します >>12。
[131] Chrome は異常終了時 (で可能なとき) に、
状態符号 1001
で理由空文字列のCloseフレームを送信するようです。
WebSocket
インターフェイス close
メソッド[59] WebSocket
インターフェイスの
close
メソッド >>58 は、
WebSocket の接続を閉じることを指示するものです。
[159] 第1引数として、WebSocket状態符号 (数値) を指定できます。 この引数は省略可能です。指定された場合は、 Closeフレームでサーバーに送られます。 いくつかの状態符号の値はプロトコルにより定められていますが、 サーバーとクライアントの裁量で決められる値の範囲もあります。
[160] 第2引数として、WebSocket接続閉じ理由 (文字列) を指定できます。 この引数は省略可能です。指定された場合は、Closeフレームでサーバーに送られます。 サーバーとクライアントの裁量で任意の文字列を使うことができますが、 UTF-8 で符号化したときに123バイト以下に収まらなければなりません。
[161] このメソッドは接続を閉じることを指示するものですが、 送受信の状態によっては、すぐには接続が閉じられない場合もあります。
[158] 本メソッドは、次のようにしなければなりません >>58。
[134] Chrome は、 接続を開いて handshake を開始した後で確立する前に
close
したとき、接続確立直後に Closeフレームを送信するようです。
handshake 失敗時は送信しません。
[90] WebSocket
オブジェクトの make disappear
は、次のようにしなければなりません >>84。
[87] WebSocket
オブジェクトのごみ収集は、
次のように規定されています。
[85] event loop step 1 時点での readyState
が、
[20] Start the WebSocket Closing Handshake は、 状態符号符号 (整数または null) と理由理由 (バイト列または null) について、 次のようにしなければなりません。
[25] Close
フレームを受信したら、次のようにします。Close
フレーム送信済みフラグが設定されていれば、CLOSING
とします >>12。
[61] 利用者エージェントは、the WebSocket closing handshake is started の際、
次のようにしなければなりません。
[7] WebSocket接続の確立やWebSocketメッセージ受信により、 WebSocket接続失敗となることがあります。
Close
フレームを送ることを求めていますが、
サーバーにはWebSocket接続確立が無く、また CLOSING
になった後で再度 Close
フレームを送るのは不適切と思われます。[35] WebSocket接続失敗以後、受信したデータを処理し続けようとしてはなりません。
これには、 Close
フレームへの返信も含まれます。 >>12
[38] サーバーが Abort the WebSocket Connection したら、 WebSocket接続を閉じる処理を実行しなければなりません >>12。
[13] WebSocket接続を閉じる時には、 下位のTCP接続を閉じます >>12。
[14] TCP接続とTLSセッションを綺麗に閉じる方法を使い、 受信したかもしれないバイトは捨てるべきです >>12。
[16] 最も通常な場合には、まず (クライアントからではなく) サーバーから TCP接続を閉じるべきです >>12。 サーバーは、直ちに TCP を閉じるべきです >>12, >>1。 クライアントは、サーバーから TCP が閉じられるのを待つべきです >>12, >>1。
TIME_WAIT
状態となります。 TIME_WAIT
状態である
最大セグメント寿命の2倍 (2MSL) の間は改めて接続を開くことができませんが、
サーバー側ならより大きなシーケンス番号の SYN
を送信すれば直ちに接続を開けるので問題となりません。 >>12[19] 例えば socket API では、
まず SHUT_WR
を指定して shutdown
を呼び出し、
0
が返されるまで recv
を呼び出し、
最後に close
を呼ぶことでこれを実装できます >>12。
[18] 十分な時間サーバーから TCP Close を受信しない場合などにはクライアントから TCP を閉じて構いません >>12, >>1。
[132] Chrome は、 Closeフレームの送信から 60s で Closeフレームを受信しないとき、 TCP 接続を閉じるようです。 Firefox は、 20s で閉じるようです。
[133] Chrome も Firefox も、 Closeフレームを送信した後 Closeフレームを受信したら、 TCP接続を閉じるようです。 切断まで Chrome は 2s 強、 Firefox は 1s 強待つようです。
[135] Closeフレームを受信した後 Closeフレームを送信してから、 Chrome は 2s、Firefox は 1s 待機した後、 TCP接続を閉じるようです。
[136] Chrome は Closeフレーム受信後にもフレームの解釈を続け、 エラーがあったらコンソールに報告します。 Firefox はそのような報告はしないので、 解釈しているのかどうかは不明です。
[15] 攻撃されている時など、必要に応じて他の方法で閉じても構いません >>12。
[137] Chrome も Firefox も、WebSocket接続失敗時にすぐに TCP接続を閉じるようです。
[27] TCP接続が閉じられた時、次のようにしなければなりません。CLOSED
に設定します >>12。
[64] 利用者エージェントは The WebSocket Connection is Closed の際、
次のようにしなければなりません。
[28] cleanly フラグは、 WebSocket接続の閉じ handshake が完了してから TCP接続が閉じられた >>12 かどうかを表します。
[78] CloseEvent
インターフェイスの
wasClean
属性は、 cleanly
に閉じられたかどうかを表します。
[79] この属性は、その属性値として設定された値を返さなければなりません >>77。データ型は boolean
で、初期値は偽です >>77。
[130] flagged as full は、バッファーが満杯でデータを送信できないことを表します。
send
メソッドからデータを送信する時に設定されることがあります。
[66] 利用者エージェントは、スクリプトに次の状況を区別できる情報を提供してはなりません >>62。
[74] このような場合のWebSocket接続閉じ符号はいずれも 1006
となります >>62。
[39] クライアントが異常終了の後再接続を試みる際は、 何らかの backoff を行うべきです。 最初の再接続は、無作為に決めた時間だけ遅延させるべきです。 0s-5s の間から無作為に決めるのが妥当でしょうが、 実装経験や応用に基づき任意の方法で決めて構いません。 それ以後の再接続は、冪乗打ち切り待機法などにより徐々に時間を長くしていくべきです。 >>12
Close
フレーム[96] Close
フレームは、 WebSocket接続を閉じる際に用いられます。
[2] opcode は、 0x8
です >>1。
Close
フレームは、制御フレームです。
[3] 閉じる理由を示す本体 (応用データ) を含んで構いません >>1。
[4] 本体がある場合、最初の2バイトはネットワークバイト順の2バイト符号無し整数でなければなりません。 この整数は、状態符号でなければなりません。 >>1
[5] 本体は更に UTF-8 符号化されたデータを含めることができます。 その解釈は WebSocket 仕様書では規定されておらず、人間可読である必要もありませんが、 デバッグなどに有用かもしれません。クライアントはこれを末端利用者に示してはなりません。 >>1
[125] 利用する場面によっては、状態符号とclose reasonは指定されていません。 そのような場合にどうするべきか、 RFC 上は明確ではありません。 実装は状況に応じた適当な値を指定できると思われます。これはデバッグには有用かもしれませんが、 一方で fingerprinting vector となったり、不必要な内部情報を送ってしまったりするかもしれませんから、 クライアントは特に注意が必要です。
[6] 応用は、 Close
フレームより後にデータフレームを送ってはなりません
>>1。
[31] 応用データが1バイトのみしかない場合にどう解釈するべきかは不明です。 非妥当なデータを受信した場合はWebSocket接続を閉じることが認められており >>42、 それに従う (というより問題を無視して閉じる処理を続ける) のが適切かもしれません。
[50] 理由が UTF-8 として妥当でなければ、WebSocket接続失敗しなければなりません >>49。
[129] Chrome は、 payload が1バイトのみの時、状態符号 1002
、
理由空文字列のCloseフレームを送信します。
理由が UTF-8 として正しくない時、状態符号 1002
、
理由 Invalid UTF-8 in Close frame
を送信します。
状態符号が 1005
、1006
の時、
状態符号 1002
理由空文字列を送信します。
Firefox はこれらの時、データなしの Closeフレームを送信します。
Firefox は状態符号が 0
の時もデータなしの
Closeフレームを送信します。
[41] Close
フレームには、閉じる理由を記述できます。
数値の状態符号と、任意の文字列を記述できます。
受信者による理由の解釈や処理方法は、 WebSocket Protocol
としては規定されていません >>12。
[124] close reason は、制御フレームの制約と状態符号が2バイトであることから、
123バイト以下である必要があります。 (UTF-8 符号化されたバイト列の制限で、
文字列の制限ではありません。) WebSocket
インターフェイスの
close
メソッドでは、この制限を超えると例外が投げられます。
[32] WebSocket接続閉じ理由は、
応用が最初に受信した Close
フレームに含まれていた閉じる理由
(UTF-8 decode without BOM を適用 >>62 した文字列)
です。そのようなものが無ければ、
空文字列です。 >>12
[82] CloseEvent
インターフェイスの
reason
属性は、WebSocket接続閉じ理由を表します。
[83] この属性は、その属性値として設定された値を返さなければなりません >>77。データ型は DOMString
で、初期値は空文字列です >>77。
close
イベント[117] close
, onclose
,
CloseEvent
を参照。
[9] RFC には同じようにみえる規定が複数あり、助動詞が MUST だったり SHOULD だり無かったりしていたり、しかし微妙に条件が違っていて矛盾しているのかどうか判断が難しかったりします。 IETF の仕様書ではよくあることですが、RFC の細部は信頼せず、 相互運用性が高いと思われる方法を推測して実装する必要がありそうです。
[138] Use utf-8 decode without BOM rather than UTF-8 decoder · whatwg/html@39a2e6c ( 版) <https://github.com/whatwg/html/commit/39a2e6cde3b4820db56fabe1859de0dc0e6ed8d9>
[139] Editorial: xref UTF-8 encode in WebSocket's close() · whatwg/html@e2bd61d ( 版) <https://github.com/whatwg/html/commit/e2bd61d1e4bd356b747e15c4e724a75eadbb25ac>