摘要:狀態(tài)碼當關(guān)閉一個連接時如在開始握手已經(jīng)完成后,發(fā)送一個關(guān)閉幀,終端可能會說明關(guān)閉的原因。表示終端由于協(xié)議錯誤中止了連接。這個狀態(tài)碼是為了給上層應(yīng)用表示連接被異常關(guān)閉如沒有發(fā)送或者接受一個關(guān)閉幀這種場景的使用而設(shè)計的。
概述
本文為 WebSocket 協(xié)議的第七章,本文翻譯的主要內(nèi)容為 WebSocket 連接關(guān)閉相關(guān)內(nèi)容。
關(guān)閉連接(協(xié)議正文) 7.1 定義 7.1.1 關(guān)閉 WebSocket 連接要關(guān)閉 WebSocket 連接,終端需要關(guān)閉底層的 TCP 連接。終端需要使用一個方法來干凈的關(guān)閉TCP連接,還有 TLS 會話,如果可能的話,拋棄后面可能受到的任意字符。終端可能會在需要的時候,通過任何方式來關(guān)閉連接,例如在收到攻擊時。
在底層的 TCP 連接中,通常大多數(shù)情況下,服務(wù)端應(yīng)該先關(guān)閉,所以是服務(wù)端而不是客戶端保持 TIME_WAIT 狀態(tài)(因為客戶端先關(guān)閉的話,這會阻止服務(wù)端在2 MSL 內(nèi)重新打開這條連接,而如果服務(wù)器處于 TIME_WAIT 狀態(tài)下,如果收到了一個帶有更大序列號的新的 SYN 包時,也能夠立即響應(yīng)重新打開連接,從而不會對服務(wù)器產(chǎn)生影響)。反常情況(例如在合理的時間后,服務(wù)端收到一個 TCP 關(guān)閉包)下,客戶端應(yīng)該開始關(guān)閉 TCP 連接。像這樣的,當服務(wù)端進入關(guān)閉 WebSocket 連接狀態(tài)時,它應(yīng)該立刻準備關(guān)閉 TCP 連接,然后當客戶端客戶端準備關(guān)閉連接時,他應(yīng)該等待服務(wù)端的 TCP 關(guān)閉包。
用 C 語言的 Berkeley socket 作為例子來展示如何徹底的關(guān)閉連接,一端需要用 SHUP_WR 調(diào)用 shutdown() 方法,調(diào)用 recv() 直到獲得一個值為 0 的表示對面也準備有序關(guān)閉連接的返回值,然后最后調(diào)用 close() 來關(guān)閉 socket 通道。
7.1.2 開始進行 WebSocket 關(guān)閉握手用一個狀態(tài)碼 code (第 7.4 節(jié))和一個可選的關(guān)閉原因 reason (第 7.1.6 節(jié))來開始 WebSocket 關(guān)閉握手,終端必須發(fā)送一個在第 5.5.1 節(jié)中描述的一樣的關(guān)閉幀,將狀態(tài)碼設(shè)置為 code 字段,將關(guān)閉原因設(shè)置為 reaons 字段。一旦終端已經(jīng)發(fā)送和收到了關(guān)閉控制幀,那么終端應(yīng)該像第 7.1.1 節(jié)中定義的一樣關(guān)閉 WebSocket 連接。
7.1.3 已經(jīng)開始 WebSocket 關(guān)閉握手在發(fā)送或者收到了關(guān)閉幀時,我們可以說已經(jīng)開始 WebSocket 關(guān)閉握手,并且 WebSocket 連接的狀態(tài)已經(jīng)到了“關(guān)閉中”(CLOSING)狀態(tài)。
7.1.4 WebSocket 連接已關(guān)閉當?shù)讓拥?TCP 連接關(guān)閉后,我們可以說WebSocket 連接已關(guān)閉,并且 WebSocket 連接已經(jīng)到了”關(guān)閉“(CLOSED)狀態(tài)。如果 TCP 連接在 WebSocket 關(guān)閉握手完成之后已經(jīng)關(guān)閉,那么我們可以說 WebSocket 連接已經(jīng)被徹底關(guān)閉。
如果 WebSocket 連接沒有被建立,我們也說WebSocket已經(jīng)關(guān)閉,但是不徹底。
7.1.5 WebSocket 關(guān)閉狀態(tài)碼就像在第 5.5.1 和第 7.4 節(jié)中定義的一樣,關(guān)閉幀可以包含一個關(guān)閉的狀態(tài)碼和指定的原因。WebSocket 連接的關(guān)閉可能是同時由另一個終端發(fā)起。WebSocket 關(guān)閉狀態(tài)碼是在第 7.4 節(jié)中定義的在第一關(guān)閉幀中的由實現(xiàn)該協(xié)議的應(yīng)用程序接收的狀態(tài)碼。如果關(guān)閉幀中沒有包含狀態(tài)碼,WebSocket 關(guān)閉狀態(tài)碼被默認為1005。如果WebSocket 已經(jīng)關(guān)閉并且終端沒有收到任何的關(guān)閉幀(例如發(fā)生了可能底層的傳輸連接突然丟失的情況),那么WebSocket 關(guān)閉狀態(tài)碼被默認為1006。
注:兩個終端可能沒有就WebSocket 關(guān)閉狀態(tài)碼的值達成一致。例如:如果遠端發(fā)送一個關(guān)閉幀,但是本地應(yīng)用沒有從它的 socket 緩沖區(qū)中讀到關(guān)閉幀的數(shù)據(jù),同時本地應(yīng)用多帶帶的決定關(guān)閉連接并且發(fā)送了一個關(guān)閉幀,那么兩個終端都發(fā)送了并且會收到一個關(guān)閉幀,同時不會發(fā)送更多的關(guān)閉幀。每一個終端會看到另一個終端發(fā)送過來的WebSocket 關(guān)閉狀態(tài)碼的狀態(tài)碼。像這樣的,在這個示例里面,有可能兩個終端都沒有協(xié)商過WebSocket 關(guān)閉狀態(tài)碼,兩個終端都幾乎在同一時間多帶帶開始 WebSocket 關(guān)閉握手。
7.1.6 WebSocket 連接關(guān)閉原因像第 5.5.1 節(jié)和第 7.4 節(jié)中定義的一樣,一個關(guān)閉幀可能包含一個用于關(guān)閉的表示原因的狀態(tài)碼,然后是 UTF-8 編碼的數(shù)據(jù),數(shù)據(jù)的解析方式是留給終端來解釋,而不在這個協(xié)議中定義。一個正在關(guān)閉中的 WebSocket 連接可能是同時從另一端開始的。WebSocket 連接關(guān)閉原因是實現(xiàn)了該協(xié)議的應(yīng)用收到的緊跟在狀態(tài)碼(第 7.4 節(jié))之后的包含在第一個關(guān)閉控制幀中的 UTF-8 編碼數(shù)據(jù)。如果在關(guān)閉控制幀中沒有這些數(shù)據(jù),那么WebSocket 連接關(guān)閉原因的值就是一個空字符串。
注:和在第 7.1.5 中被提到的邏輯一樣,兩個終端可能沒有協(xié)商過WebSocket 連接關(guān)閉原因。
7.1.7 WebSocket 連接失效某些算法和規(guī)范要求終端有WebSocket 連接失效。為了實現(xiàn)這些,客戶端必須關(guān)閉 WebSocket 連接,并且可以用一個合適的方式向用戶上報相關(guān)問題(尤其是對開發(fā)者有幫助的內(nèi)容)。相似的,為了實現(xiàn)這個,服務(wù)端必須關(guān)閉 WebSocket 連接,并且應(yīng)該用日志記錄這個問題。
如果在此之前WebSocket 已經(jīng)建立連接,此時終端需要讓WebSocket 連接失效,那么在進行關(guān)閉 WebSocket 連接之前,終端需要發(fā)送一個包含恰當?shù)臓顟B(tài)碼(第 7.4 節(jié))。終端在確認另一端沒有能力接收或者處理關(guān)閉幀時,可能會選擇省略發(fā)送關(guān)閉幀,從而在一開始就進入正常錯誤流程導致 WebSocket 連接關(guān)閉。終端在接到WebSocket 連接失效的指令后,不能繼續(xù)嘗試處理來自另一端的數(shù)據(jù)(包括響應(yīng)的關(guān)閉幀)。
除了上面說到的場景和應(yīng)用層指定的場景(例如:腳本使用了 WebSocket 的 API)外,客戶端不應(yīng)該關(guān)閉連接。
7.2 異常關(guān)閉 7.2.1 客戶端主動關(guān)閉在開始握手中的某些特定算法,需要客戶端讓WebSocket 連接失效。為了實現(xiàn)這些,客戶端必須像第 7.1.7 節(jié)中定義的一樣讓WebSocket 連接失敗。
如果任意一端底層的傳輸連接意外丟失,客戶端必須讓WebSocket 連接失敗。
除了上面指定的情況和應(yīng)用層的約束(例如,腳本使用了 WebSocket 的 API)外,客戶端不應(yīng)該關(guān)閉連接。
7.2.2 服務(wù)端主動關(guān)閉在開始監(jiān)建立連接握手時,有些算法要求或者推薦服務(wù)端終端 WebSocket 連接。為了實現(xiàn)這些,服務(wù)端必須關(guān)閉 WebSocket 連接(第 7.1.1 節(jié))。
7.2.3 從異常關(guān)閉中恢復(fù)導致異常關(guān)閉的原因有很多。例如是由于一個臨時的錯誤導致的關(guān)閉,在這種情況下能夠恢復(fù)就能夠帶來一個穩(wěn)定的連接,恢復(fù)正常的操作。有些問題也有可能是一個非臨時的問題導致的,在這種情況下如果每個客戶端都遇到了異常的關(guān)閉,客戶端立刻重試連接并且不間斷情況下,服務(wù)端可能會收到由于大量客戶端重新連接帶來的拒絕服務(wù)攻擊。最終的結(jié)果就是這個方案可能會導致服務(wù)沒有辦法及時的恢復(fù),或者讓服務(wù)恢復(fù)變得困難的多。
為了避免這個問題,客戶端應(yīng)該在異常終端嘗試恢復(fù)連接時,使用在這一節(jié)中定義的一些備選策略。
第一次嘗試恢復(fù)連接應(yīng)該在一個隨機長度時間后。隨機事件的參數(shù)如何選擇,這個交給客戶端來決定;選擇 0 到 5 秒之間的隨機值是一個合理的初始延時,但是客戶端可以根據(jù)自己的經(jīng)驗和特定的應(yīng)用來選擇不同長度的時間延時。
如果第一次重試連接失敗,接下來的連接的延時應(yīng)該變大,使用如截斷二進制指數(shù)退避方法(譯者注:解決以太網(wǎng)碰撞算法,見截斷二進制質(zhì)數(shù)退避算法)等來進行設(shè)置這個延時。
7.3 連接正常關(guān)閉服務(wù)端可以在任意需要時關(guān)閉 WebSocket 連接。客戶端不應(yīng)該任意關(guān)閉 WebSocket 連接。在任一情況中,終端要發(fā)起關(guān)閉都必須遵循開始 WebSocket 連接關(guān)閉的步驟。
7.4 狀態(tài)碼當關(guān)閉一個連接時(如:在開始握手已經(jīng)完成后,發(fā)送一個關(guān)閉幀),終端可能會說明關(guān)閉的原因。終端的這個原因的描述和終端應(yīng)該采取的行動,在這個文檔中都沒有說明。這個文檔提前定義了一些可能用于擴展、框架和終端應(yīng)用的狀態(tài)碼和狀態(tài)碼范圍。這些狀態(tài)碼和任何有關(guān)聯(lián)的的文本消息在關(guān)閉幀中都是可選的。
7.4.1 定義狀態(tài)碼在發(fā)送一個關(guān)閉幀時,終端可以提前定義如下的狀態(tài)碼。
1000
1000 表示一個正常的關(guān)閉,意味著連接建立的目標已經(jīng)完成了。
1001
1001 表示終端已經(jīng)“走開”,例如服務(wù)器停機了或者在瀏覽器中離開了這個頁面。
1002
1002 表示終端由于協(xié)議錯誤中止了連接。
1003
1003 表示終端由于收到了一個不支持的數(shù)據(jù)類型的數(shù)據(jù)(如終端只能怪理解文本數(shù)據(jù),但是收到了一個二進制數(shù)據(jù))從而關(guān)閉連接。
1004
保留字段。這意味著這個狀態(tài)碼可能會在將來被定義。
1005
1005 是一個保留值并且不能被終端當做一個關(guān)閉幀的狀態(tài)碼。這個狀態(tài)碼是為了給上層應(yīng)用表示當前沒有狀態(tài)碼。
1006
1006 是一個保留值并且不能被終端當做一個關(guān)閉幀的狀態(tài)碼。這個狀態(tài)碼是為了給上層應(yīng)用表示連接被異常關(guān)閉如沒有發(fā)送或者接受一個關(guān)閉幀這種場景的使用而設(shè)計的。
1007
1007 表示終端因為收到了類型不連續(xù)的消息(如非 UTF-8 編碼的文本消息)導致的連接關(guān)閉。
1008
1008 表示終端是因為收到了一個違反政策的消息導致的連接關(guān)閉。這是一個通用的狀態(tài)碼,可以在沒有什么合適的狀態(tài)碼(如 1003 或者 1009)時或者可能需要隱藏關(guān)于政策的具體信息時返回。
1009
1009 表示終端由于收到了一個太大的消息無法進行處理從而關(guān)閉連接。
1010
1010 表示終端(客戶端)因為預(yù)期與服務(wù)端協(xié)商一個或者多個擴展,但是服務(wù)端在 WebSocket 握手中沒有響應(yīng)這個導致的關(guān)閉。需要的擴展清單應(yīng)該出現(xiàn)在關(guān)閉幀的原因(reason)字段中。
1001
1001 表示服務(wù)端因為遇到了一個意外的條件阻止它完成這個請求從而導致連接關(guān)閉。
1015
1015 是一個保留值,不能被終端設(shè)置到關(guān)閉幀的狀態(tài)碼中。這個狀態(tài)碼是用于上層應(yīng)用來表示連接失敗是因為 TLS 握手失?。ㄈ绶?wù)端證書沒有被驗證過)導致的關(guān)閉的。
7.4.2 保留狀態(tài)碼范圍0-999
0-999 的狀態(tài)碼都沒有被使用。
1000-2999
1000-2999 的狀態(tài)碼是在這個文檔、將來的修訂和擴展中定義的保留字段,用于永久的可用的公共文檔。
3000-3999
3000-3999 的狀態(tài)碼是保留給庫、框架和應(yīng)用使用的。這些狀態(tài)碼被IANA直接注冊了。這些狀態(tài)碼在這篇文檔中沒有進行解釋。
4000-4999
40000-4999 的狀態(tài)碼是保留下來私用的,因此這些狀態(tài)碼不能被注冊。這些狀態(tài)碼可以使用在 WebSocket 應(yīng)用之前的協(xié)議上。這些狀態(tài)碼在這篇文檔中沒有進行解釋。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/101850.html
摘要:概述經(jīng)過半年的搗鼓,終于將協(xié)議全篇翻譯完成?,F(xiàn)在將所有章節(jié)全部整理到一篇文章中,方便大家閱讀。如果大家想看具體的翻譯文檔,可以去我的中查看。大家有相關(guān)類型的需要,建議大家可以嘗試下。 概述 經(jīng)過半年的搗鼓,終于將 WebSocket 協(xié)議(RFC6455)全篇翻譯完成?,F(xiàn)在將所有章節(jié)全部整理到一篇文章中,方便大家閱讀。如果大家想看具體的翻譯文檔,可以去我的GitHub中查看。 具體章節(jié)...
摘要:最終形成服務(wù)器端的握手響應(yīng)必需。出于安全考慮和避免網(wǎng)絡(luò)截獲,客戶端發(fā)送的數(shù)據(jù)幀必須進行掩碼處理后才能發(fā)送到服務(wù)器,不論是否是在安全協(xié)議上都要進行掩碼處理。服務(wù)器如果沒有收到掩碼處理的數(shù)據(jù)幀時應(yīng)該關(guān)閉連接,發(fā)送一個的狀態(tài)碼。 首先 長連接:一個連接上可以連續(xù)發(fā)送多個數(shù)據(jù)包,在連接期間,如果沒有數(shù)據(jù)包發(fā)送,需要雙方發(fā)鏈路檢查包。 TCP/IP:TCP/IP屬于傳輸層,主要解決數(shù)據(jù)在網(wǎng)絡(luò)中的...
摘要:服務(wù)端確認協(xié)議版本,升級為協(xié)議。自己寫了一個例子,服務(wù)端在開始連接后,利用定時器主動向客戶端發(fā)送隨機數(shù),客戶端也可以發(fā)給服務(wù)器消息,然后服務(wù)器返回這條消息給客戶端。 寫在前面 webSocket是一項可以讓服務(wù)器將數(shù)據(jù)主動推送給客戶端的技術(shù)。前幾天寫了一個日志功能,日志數(shù)據(jù)需要實時更新。正好項目中有封裝好的WebSocket組件,且接口支持webSocket,就用它實現(xiàn)了。也是第一次用...
摘要:用實現(xiàn)簡單協(xié)議從瀏覽器說起瀏覽器提供的非常簡潔。創(chuàng)建連接連接建立時的回調(diào)收到消息時的回調(diào)連接出錯時的回調(diào)連接終止時的回調(diào)發(fā)送消息告訴我們也就是說,在創(chuàng)建對象時,瀏覽器嘗試與服務(wù)端建立連接發(fā)送請求建立個服務(wù)端一旦收到數(shù)據(jù),就會觸發(fā)。 用 Node 實現(xiàn)簡單 WebSocket 協(xié)議 從瀏覽器 WebSocket API 說起 瀏覽器提供的 WebSocket API 非常簡潔。 let...
摘要:服務(wù)端確認協(xié)議版本,升級為協(xié)議。自己寫了一個例子,服務(wù)端在開始連接后,利用定時器主動向客戶端發(fā)送隨機數(shù),客戶端也可以發(fā)給服務(wù)器消息,然后服務(wù)器返回這條消息給客戶端。做的事情就是給頁面的元素綁定事件。 寫在前面webSocket是一項可以讓服務(wù)器將數(shù)據(jù)主動推送給客戶端的技術(shù)。前幾天寫了一個日志功能,日志數(shù)據(jù)需要實時更新。正好項目中有封裝好的WebSocket組件,且接口支持webSock...
閱讀 3508·2023-04-26 02:41
閱讀 2642·2023-04-26 00:14
閱讀 3100·2021-08-11 10:22
閱讀 1442·2019-12-27 11:38
閱讀 3665·2019-08-29 18:34
閱讀 2461·2019-08-29 12:13
閱讀 3035·2019-08-26 18:26
閱讀 2079·2019-08-26 16:49