7 關(guān)閉連接

2018-02-24 15:53 更新

關(guān)閉連接

7.1.定義

7.1.1.關(guān)閉WebSocket連接

關(guān)閉WebSocket連接,端點(diǎn)需關(guān)閉底層TCP連接。端點(diǎn)應(yīng)該使用一個(gè)方法完全地關(guān)閉TCP連接,以及TLS會(huì)話,如果合適,丟棄任何可能已經(jīng)接收的尾隨的字節(jié)。當(dāng)必要時(shí)端點(diǎn)可以通過(guò)任何可用的手段關(guān)閉連接,例如當(dāng)受到攻擊時(shí)。

底層TCP連接,在大多數(shù)正常情況下,應(yīng)該首先被服務(wù)器關(guān)閉,所以它持有TIME_WAIT狀態(tài)而不是客戶端(因?yàn)檫@會(huì)防止它在2個(gè)報(bào)文最大生存時(shí)間(2MLS)內(nèi)重新打開(kāi)連接,然而當(dāng)一個(gè)新的帶有更高的seq number的SYN時(shí)沒(méi)有對(duì)應(yīng)的服務(wù)器影響TIME_WAIT連接被立即重新打開(kāi))。在異常情況下(例如在一個(gè)合理的時(shí)間量后沒(méi)有接收到服務(wù)器的TCP Close)客戶端可以發(fā)起TCP Close。因此,當(dāng)服務(wù)器被指示關(guān)閉WebSocket連接,它應(yīng)該立即發(fā)起一個(gè)TCP Close,且當(dāng)客戶端被知識(shí)也這么做時(shí),它應(yīng)該等待服務(wù)器的一個(gè)TCP Close。

例如一個(gè)如何使用Berkeley socket在C中得到完全地關(guān)閉的例子,一端會(huì)在socket上以SHUT_WR調(diào)用shutdown(),調(diào)用recv()直到獲得一個(gè)指示那個(gè)節(jié)點(diǎn)也已經(jīng)執(zhí)行了一個(gè)有序關(guān)閉的0返回值,且最終在socket上調(diào)用close()方法。

7.1.2.啟動(dòng)WebSocket關(guān)閉階段握手

為了啟動(dòng)WebSocket關(guān)閉階段握手,其帶有一個(gè)狀態(tài)碼(7.4節(jié))/code/和一個(gè)可選的關(guān)閉原因(7.1.6節(jié))/reason/,一個(gè)端點(diǎn)必須按照5.5.1節(jié)的描述發(fā)送一個(gè)Close控制幀,其狀態(tài)碼設(shè)置為/code/且其關(guān)閉原因設(shè)置為/reason/。一旦一個(gè)端點(diǎn)已經(jīng)發(fā)送并接收到一個(gè)Close控制幀,那個(gè)端點(diǎn)應(yīng)該按照7.1.1節(jié)的描述關(guān)閉WebSocket連接。

7.1.3. WebSocket關(guān)閉階段握手已啟動(dòng)

一旦發(fā)送或接收到一個(gè)Close控制幀,這就是說(shuō),WebSocket 關(guān)閉階段握手已啟動(dòng),且WebSocket連接處于CLOSING狀態(tài)。

7.1.4. WebSocket已關(guān)閉

當(dāng)?shù)讓覶CP連接已關(guān)閉,這就是說(shuō)WebSocket連接已關(guān)閉且WebSocket連接處于CLOSED狀態(tài)。如果TCP連接在WebSocket關(guān)閉階段我是已經(jīng)完成后被關(guān)閉,WebSocket連接被說(shuō)成已經(jīng)完全地關(guān)閉了。 如果WebSocket連接不能被建立,這就是說(shuō),WebSocket連接關(guān)閉了,但不是完全的。

7.1.5.WebSocket連接關(guān)閉代碼

按照5.5.1和7.4節(jié)的定義,一個(gè)Close控制幀可以包含一個(gè)表示關(guān)閉原因的狀態(tài)碼。一個(gè)正關(guān)閉的WebSocket連接可以同時(shí)由兩個(gè)端點(diǎn)初始化。WebSocket連接Close Code定義為包含在由實(shí)現(xiàn)該協(xié)議的應(yīng)用接收到的第一個(gè)Close控制幀的狀態(tài)碼(7.4節(jié))。如果這個(gè)Close控制幀不包含狀態(tài)碼,WebSocket連接Close Code被認(rèn)為是1005。如果WebSocket連接已經(jīng)關(guān)閉且端點(diǎn)沒(méi)有接收到Close狀態(tài)碼(例如可能發(fā)生在底層傳輸連接丟失時(shí)),WebSocket連接Close Code被認(rèn)為是1006。

注意:兩個(gè)端點(diǎn)可以有不一致的WebSocket連接關(guān)閉代碼。例如,如果遠(yuǎn)程端點(diǎn)發(fā)送了一個(gè)Close幀,但本地應(yīng)用還沒(méi)有從它的socket接收緩沖區(qū)中讀到包含Close幀的數(shù)據(jù),且本地應(yīng)用獨(dú)立地決定關(guān)閉連接和發(fā)送一個(gè)Close幀,兩個(gè)端點(diǎn)都將發(fā)送和接收Close幀且將不發(fā)送更多的Close幀。每一個(gè)端點(diǎn)將看見(jiàn)另一端發(fā)送的以WebSocket連接關(guān)閉代碼結(jié)束的狀態(tài)碼。例如,在兩個(gè)端點(diǎn)獨(dú)立且在大致相同的時(shí)間同時(shí)開(kāi)啟WebSocket關(guān)閉階段握手的情況下,兩個(gè)端點(diǎn)可以有不一致的WebSocket連接關(guān)閉代碼是可能的。

7.1.6. WebSocket連接關(guān)閉原因

按照5.5.1和7.4節(jié)的定義,一個(gè)控Close控制幀可以包含一個(gè)指示關(guān)閉原因的狀態(tài)碼,接著是UTF-8編碼的數(shù)據(jù),上述數(shù)據(jù)留給斷點(diǎn)解釋且本協(xié)議沒(méi)有定義。WebSocket連接的關(guān)閉可以被任何一個(gè)端點(diǎn)初始化,可能同時(shí)發(fā)生。WebSocket 連接關(guān)閉原因由跟在包含在實(shí)現(xiàn)該協(xié)議的應(yīng)用接收到的第一個(gè)Close控制幀狀態(tài)碼(7.4節(jié))后邊的UTF-8編碼的數(shù)據(jù)定義。如果Close控制幀中沒(méi)有這樣的數(shù)據(jù),WebSocket連接關(guān)閉原因是空字符串。

注意:按照7.1.5節(jié)指出的相同的邏輯,兩個(gè)端點(diǎn)可以有不一致的WebSocket連接關(guān)閉原因。

7.1.7.失敗WebSocket連接

某些算法和規(guī)范要求端點(diǎn)失敗WebSocket連接。要做到這一點(diǎn),客戶端必須關(guān)閉WebSocket連接,并可以以適當(dāng)?shù)姆绞桨褑?wèn)題報(bào)告給用戶(這將對(duì)開(kāi)發(fā)人員非常有用的)。

同樣的,為了做到這一點(diǎn),服務(wù)器必須關(guān)閉WebSocket連接,并應(yīng)該記錄下問(wèn)題。

如果已建立的WebSocket連接在端點(diǎn)需要失敗WebsSocket連接之前,端點(diǎn)應(yīng)該在處理關(guān)閉WebSocket連接之前發(fā)送一個(gè)帶有適當(dāng)狀態(tài)碼的Close幀(7.4節(jié))。

如果端點(diǎn)認(rèn)為另一邊不太可能收到并處理關(guān)閉幀可以省略發(fā)送一個(gè)關(guān)閉幀,因?yàn)殄e(cuò)誤的性質(zhì),導(dǎo)致WebSocket連接失敗擺在首要位置。端點(diǎn)必須在被指示為失敗WebSocket端點(diǎn)之后不繼續(xù)嘗試處理來(lái)自遠(yuǎn)程端點(diǎn)的數(shù)據(jù)(包括響應(yīng)關(guān)閉幀)。

除上邊指出的或由應(yīng)用層指定的(例如,使用WebSocket API的腳本),客戶端應(yīng)該關(guān)閉連接。

7.2.異常關(guān)閉

7.2.1.客戶端發(fā)起的關(guān)閉

某些算法,尤其在打開(kāi)階段握手期間,需要客戶端失敗WebSocket連接。為了做到這一點(diǎn),客戶端必須按照7.1.7節(jié)定義的那樣失敗WebSocket連接。

如果在任何時(shí)候,底層的傳輸層連接意外丟失,客戶端必須失敗WebSocket連接。 除上邊指出的或由應(yīng)用層指定的(例如,使用WebSocket API的腳本),客戶端應(yīng)該關(guān)閉連接。

7.2.2.服務(wù)端發(fā)起的關(guān)閉

某些算法需要或推薦服務(wù)端在打開(kāi)階段握手期間中斷WebSocket連接。為了做到這一點(diǎn),服務(wù)端必須簡(jiǎn)單地關(guān)閉WebSocket連接(7.1.1節(jié))。

7.2.3.從異常關(guān)閉中恢復(fù)

異常關(guān)閉可能由任何原因引起。這樣的關(guān)閉可能是一個(gè)瞬時(shí)錯(cuò)誤導(dǎo)致的,在這種情況下重新連接可能導(dǎo)致一個(gè)好的連接和一個(gè)重新開(kāi)始的正常操作。這樣的關(guān)閉也可能是一個(gè)非瞬時(shí)問(wèn)題的導(dǎo)致的,在這種情況下如果每個(gè)部署的客戶端遇到異常關(guān)閉并立即且持續(xù)地的嘗試重新連接,服務(wù)端可能會(huì)因?yàn)榇罅康目蛻舳藝L試重新連接遇到的拒絕服務(wù)攻擊。這種情況的最終結(jié)果可能是服務(wù)不能及時(shí)的恢復(fù)或恢復(fù)是更加困難。

為了避免這個(gè),當(dāng)客戶端遇到本節(jié)描述的異常關(guān)閉之后嘗試重新連接時(shí),應(yīng)該使用某種形式的補(bǔ)償。

第一個(gè)重新連接嘗試應(yīng)該延遲一個(gè)隨機(jī)的時(shí)間量。這種隨機(jī)延遲的參數(shù)的選擇留給客戶端決定;一個(gè)可隨機(jī)選擇的的值在0到5秒是一個(gè)合理的初始延遲,不過(guò)客戶端可以選擇不同的間隔由于其選擇一個(gè)延遲長(zhǎng)度基于實(shí)現(xiàn)經(jīng)驗(yàn)和特定的應(yīng)用。

第一次重新連接嘗試失敗,隨后的重新連接嘗試應(yīng)該延遲遞增的時(shí)間量,使用的方法如截?cái)喽M(jìn)制指數(shù)退避算法。

7.3.正常連接關(guān)閉

服務(wù)端在需要時(shí)可能關(guān)閉WebSocket連接??蛻舳瞬荒茈S意關(guān)閉WebSocket連接。在這兩種情況下,端點(diǎn)通過(guò)如下過(guò)程開(kāi)始WebSocket關(guān)閉握手初始化一個(gè)關(guān)閉(7.1.2節(jié))。

7.4.狀態(tài)碼

當(dāng)關(guān)閉一個(gè)已經(jīng)建立的連接(例如,當(dāng)在打開(kāi)階段握手已經(jīng)完成后發(fā)送一個(gè)關(guān)閉幀),端點(diǎn)可以表明關(guān)閉的原因。由端點(diǎn)解釋這個(gè)原因,并且端點(diǎn)應(yīng)該給這個(gè)原因采取動(dòng)作,本規(guī)范是沒(méi)有定義的。本規(guī)范定義了一組預(yù)定義的狀態(tài)碼,并指定哪些范圍可以被擴(kuò)展、框架和最終應(yīng)用使用。狀態(tài)碼和任何相關(guān)的文本消息是關(guān)閉幀的可選的組件。

7.4.1.定義的狀態(tài)碼

當(dāng)發(fā)送關(guān)閉幀時(shí)端點(diǎn)可以使用如下預(yù)定義的狀態(tài)碼。

  • 1000

    1000表示正常關(guān)閉,意思是建議的連接已經(jīng)完成了。

  • 1001

    1001表示端點(diǎn)“離開(kāi)”(going away),例如服務(wù)器關(guān)閉或?yàn)g覽器導(dǎo)航到其他頁(yè)面。

  • 1002

    1002表示端點(diǎn)因?yàn)閰f(xié)議錯(cuò)誤而終止連接。

  • 1003

    1003表示端點(diǎn)由于它收到了不能接收的數(shù)據(jù)類(lèi)型(例如,端點(diǎn)僅理解文本數(shù)據(jù),但接收到了二進(jìn)制消息)而終止連接。

  • 1004 保留??赡茉趯?lái)定義其具體的含義。

  • 1005

    1005是一個(gè)保留值,且不能由端點(diǎn)在關(guān)閉控制幀中設(shè)置此狀態(tài)碼。它被指定用在期待一個(gè)用于表示沒(méi)有狀態(tài)碼是實(shí)際存在的狀態(tài)碼的應(yīng)用中。

  • 1006

    1006是一個(gè)保留值,且不能由端點(diǎn)在關(guān)閉控制幀中設(shè)置此狀態(tài)碼。它被指定用在期待一個(gè)用于表示連接異常關(guān)閉的狀態(tài)碼的應(yīng)用中。

  • 1007

    1007表示端點(diǎn)因?yàn)橄⒅薪邮盏降臄?shù)據(jù)是不符合消息類(lèi)型而終止連接(比如,文本消息中存在非UTF-8[RFC3629]數(shù)據(jù))。

  • 1008

    1008表示端點(diǎn)因?yàn)榻邮盏降南⑦`反其策略而終止連接。這是一個(gè)當(dāng)沒(méi)有其他合適狀態(tài)碼(例如1003或1009)或如果需要隱藏策略的具體細(xì)節(jié)時(shí)能被返回的通用狀態(tài)碼。

  • 1009

    1009表示端點(diǎn)因接收到的消息對(duì)它的處理來(lái)說(shuō)太大而終止連接。

  • 1010

    1010表示端點(diǎn)(客戶端)因?yàn)樗谕?wù)器協(xié)商一個(gè)或多個(gè)擴(kuò)展,但服務(wù)器沒(méi)有在WebSocket握手響應(yīng)消息中返回它們而終止連接。 所需要的擴(kuò)展列表應(yīng)該出現(xiàn)在關(guān)閉幀的/reason/部分。

    注意,這個(gè)狀態(tài)碼不能被服務(wù)器端使用,因?yàn)樗梢允ebSocket握手。

  • 1011

    1011表示服務(wù)器端因?yàn)橛龅搅艘粋€(gè)不期望的情況使它無(wú)法滿足請(qǐng)求而終止連接。

  • 1015

    1015是一個(gè)保留值,且不能由端點(diǎn)在關(guān)閉幀中被設(shè)置為狀態(tài)碼。它被指定用在期待一個(gè)用于表示連接由于執(zhí)行TLS握手失敗而關(guān)閉的狀態(tài)碼的應(yīng)用中(比如,服務(wù)器證書(shū)不能驗(yàn)證)。

7.4.2.保留的狀態(tài)碼范圍

  • 0-999

    0-999范圍內(nèi)的狀態(tài)碼不被使用。

  • 1000-2999

    1000-2999范圍內(nèi)的狀態(tài)碼保留給本協(xié)議、其未來(lái)的修訂和一個(gè)永久的和現(xiàn)成的公共規(guī)范中指定的擴(kuò)展的定義。

  • 3000-3999

    3000-3999范圍內(nèi)的狀態(tài)碼保留給庫(kù)、框架和應(yīng)用使用。這些狀態(tài)碼直接向IANA注冊(cè)。本規(guī)范未定義這些狀態(tài)碼的解釋。

  • 4000-4999

    4000-4999范圍內(nèi)的狀態(tài)碼保留用于私有使用且因此不能被注冊(cè)。這些狀態(tài)碼可以被在WebSocket應(yīng)用之間的先前的協(xié)議使用。本規(guī)范未定義這些狀態(tài)碼的解釋。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)