5 數(shù)據(jù)幀

2018-02-24 15:53 更新

數(shù)據(jù)幀

5.1概述

在WebSocket協(xié)議中,數(shù)據(jù)使用幀序列來(lái)傳輸。為避免混淆網(wǎng)絡(luò)中間件(例如攔截代理)和出于安全原因,第10.3節(jié)進(jìn)一步討論,客戶(hù)端必須掩碼(mask)它發(fā)送到服務(wù)器的所有幀(更多詳細(xì)信息請(qǐng)參見(jiàn)5.3節(jié))。(注意不管WebSocket協(xié)議是否運(yùn)行在TLS至上,掩碼都要做。) 當(dāng)收到一個(gè)沒(méi)有掩碼的幀時(shí),服務(wù)器必須關(guān)閉連接。在這種情況下,服務(wù)器可能發(fā)送一個(gè)定義在7.4.1節(jié)的狀態(tài)碼1002(協(xié)議錯(cuò)誤)的Close幀。服務(wù)器必須不掩碼發(fā)送到客戶(hù)端的所有幀。如果客戶(hù)端檢測(cè)到掩碼的幀,它必須關(guān)閉連接。在這種情況下,它可能使用定義在7.4.1節(jié)的狀態(tài)碼1002(協(xié)議錯(cuò)誤)。(這些規(guī)則可能在未來(lái)規(guī)范中放寬。)

基本幀協(xié)議定義了帶有操作碼(opcode)的幀類(lèi)型、負(fù)載長(zhǎng)度、和用于“擴(kuò)展數(shù)據(jù)”與“應(yīng)用數(shù)據(jù)”及它們一起定義的“負(fù)載數(shù)據(jù)”的指定位置。某些字節(jié)和操作嗎保留用于未來(lái)協(xié)議的擴(kuò)展。

一個(gè)數(shù)據(jù)幀可以被客戶(hù)端或者服務(wù)器在打開(kāi)階段握手完成之后和端點(diǎn)發(fā)送Close幀之前的任何時(shí)候傳輸(5.5.1節(jié))。

5.2基本幀協(xié)議

用于數(shù)據(jù)傳輸部分的報(bào)文格式是通過(guò)本節(jié)中詳細(xì)描述的ABNF來(lái)描述。(注意,不像本文檔的其他章節(jié),本節(jié)中的ABNF是在位(bit)組上操作。每一個(gè)位組的長(zhǎng)度在注釋中指出。在編碼報(bào)文時(shí),最重要的位是在ABNF的最左邊。)下圖給出了幀的高層次概述。在下圖和在本節(jié)后邊指定的ABNF之間沖突的,這個(gè)圖表是權(quán)威的。

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-------+-+-------------+-------------------------------+
 |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
 |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
 |N|V|V|V|       |S|             |   (if payload len==126/127)   |
 | |1|2|3|       |K|             |                               |
 +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
 |     Extended payload length continued, if payload len == 127  |
 + - - - - - - - - - - - - - - - +-------------------------------+
 |                               |Masking-key, if MASK set to 1  |
 +-------------------------------+-------------------------------+
 | Masking-key (continued)       |          Payload Data         |
 +-------------------------------- - - - - - - - - - - - - - - - +
 :                     Payload Data continued ...                :
 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
 |                     Payload Data continued ...                |
 +---------------------------------------------------------------+

FIN:1 bit

指示這個(gè)是消息的最后片段。第一個(gè)片段可能也是最后的片段。

RSV1, RSV2, RSV3: 每個(gè)1 bit

必須是0,除非一個(gè)擴(kuò)展協(xié)商為非零值定義含義。如果收到一個(gè)非零值且沒(méi)有協(xié)商的擴(kuò)展定義這個(gè)非零值的含義,接收端點(diǎn)必須失敗WebSokcket連接

Opcode: 4 bits

定義了“負(fù)載數(shù)據(jù)”的解釋。如果收到一個(gè)未知的操作碼,接收端點(diǎn)必須失敗WebSocket連接。定義了以下值。

  • %x0 代表一個(gè)繼續(xù)幀
  • %x1 代表一個(gè)文本幀
  • %x2 代表一個(gè)二進(jìn)制幀
  • %x3-7 保留用于未來(lái)的非控制幀
  • %x8 代表連接關(guān)閉
  • %x9 代表ping
  • %xA 代表pong
  • %xB-F 保留用于未來(lái)的控制幀

Mask: 1 bit

定義是否“負(fù)載數(shù)據(jù)”是掩碼的。如果設(shè)置為1,一個(gè)掩碼鍵出現(xiàn)在masking-key,且這個(gè)是用于根據(jù)5.3節(jié)解掩碼(unmask)“負(fù)載數(shù)據(jù)”。從客戶(hù)端發(fā)送到服務(wù)器的所有幀有這個(gè)位設(shè)置為1。

Payload length: 7 bits, 7+16 bits, 或者 7+64 bits

“負(fù)載數(shù)據(jù)”的長(zhǎng)度,以字節(jié)為單位:如果0-125,這是負(fù)載長(zhǎng)度。如果126,之后的兩字節(jié)解釋為一個(gè)16位的無(wú)符號(hào)整數(shù)是負(fù)載長(zhǎng)度。如果127,之后的8字節(jié)解釋為一個(gè)64位的無(wú)符號(hào)整數(shù)(最高有效位必須是0)是負(fù)載長(zhǎng)度。多字節(jié)長(zhǎng)度數(shù)量以網(wǎng)絡(luò)字節(jié)順序來(lái)表示。注意,在所有情況下,最小數(shù)量的字節(jié)必須用于編碼長(zhǎng)度,例如,一個(gè)124字節(jié)長(zhǎng)的字符串的長(zhǎng)度不能被編碼為序列126,0,124。負(fù)載長(zhǎng)度是“擴(kuò)展數(shù)據(jù)”長(zhǎng)度+“應(yīng)用數(shù)據(jù)”長(zhǎng)度?!皵U(kuò)展數(shù)據(jù)”長(zhǎng)度可能是零,在這種情況下,負(fù)載長(zhǎng)度是“應(yīng)用數(shù)據(jù)”長(zhǎng)度。

Masking-key: 0 or 4 bytes

客戶(hù)端發(fā)送到服務(wù)器的所有幀通過(guò)一個(gè)包含在幀中的32位值來(lái)掩碼。如果mask位設(shè)置為1,則該字段存在,如果mask位設(shè)置為0,則該字段缺失。詳細(xì)信息請(qǐng)參見(jiàn)5.3節(jié) 客戶(hù)端到服務(wù)器掩碼。

Payload data: (x+y) bytes

“負(fù)載數(shù)據(jù)”定義為“擴(kuò)展數(shù)據(jù)”連接“應(yīng)用數(shù)據(jù)”。

Extension data: x bytes

“擴(kuò)展數(shù)據(jù)”是0字節(jié)除非已經(jīng)協(xié)商了一個(gè)擴(kuò)展。任何擴(kuò)展必須指定“擴(kuò)展數(shù)據(jù)”的長(zhǎng)度,或長(zhǎng)度是如何計(jì)算的,以及擴(kuò)展如何使用必須在打開(kāi)階段握手期間協(xié)商。 如果存在,“擴(kuò)展數(shù)據(jù)”包含在總負(fù)載長(zhǎng)度中。

Application data: y bytes

任意的“應(yīng)用數(shù)據(jù)”,占用“擴(kuò)展數(shù)據(jù)”之后幀的剩余部分?!皯?yīng)用數(shù)據(jù)”的長(zhǎng)度等于負(fù)載長(zhǎng)度減去“擴(kuò)展數(shù)據(jù)”長(zhǎng)度。

基本幀協(xié)議是由以下ABNF[RFC5234]正式定義。重要的是要注意這個(gè)數(shù)據(jù)是二進(jìn)制表示的,而不是ASCII字符。因此,一個(gè)1位長(zhǎng)度的字段取值為%x0 / %x1 是表示為單個(gè)位,其值為0或1,不是以ASCII編碼代表字符“0”或“1”的完整的字節(jié)(8位位組)。4位長(zhǎng)度的字段值介于%0-F之間,是通過(guò)4位表示的,不是通過(guò)ASCII字符或這些值的完整字節(jié)(8位位組)。[RFC5234]沒(méi)有指定字符編碼:“規(guī)則解析為最終值的字符串,有時(shí)候被稱(chēng)為字符。在ABNF中,一個(gè)字符僅僅是一個(gè)非負(fù)整數(shù)。在某些上下文中,一個(gè)值到一個(gè)字符集的特定映射(編碼)將被指定?!?在這里,指定的編碼是二進(jìn)制編碼,每一個(gè)最終值是編碼到指定數(shù)量的比特中,每個(gè)字段是不同的。

ws-frame                = frame-fin           ; 1位長(zhǎng)度
                          frame-rsv1         ; 1位長(zhǎng)度
                          frame-rsv2         ; 1位長(zhǎng)度
                          frame-rsv3         ; 1位長(zhǎng)度
                          frame-opcode       ; 4位長(zhǎng)度
                          frame-masked       ; 1位長(zhǎng)度
                          frame-payload-length   ; 或者 7、 7+16、
                                               ; 或者7+64 位長(zhǎng)度
                          [ frame-masking-key ]  ; 32位長(zhǎng)度
                          frame-payload-data     ; n*8位長(zhǎng)度; n>=0

frame-fin               = %x0 ; 這條消息后續(xù)還有更多的幀
                        / %x1 ; 這條消息的最終幀
                              ; 1位長(zhǎng)度

frame-rsv1              = %x0 / %x1
                          ; 1位長(zhǎng)度,必須是0,除非協(xié)商其他

frame-rsv2              = %x0 / %x1
                          ; 1位長(zhǎng)度,必須是0,除非協(xié)商其他

frame-rsv3              = %x0 / %x1
                          ; 1位長(zhǎng)度,必須是0,除非協(xié)商其他

frame-opcode            = frame-opcode-non-control /
                         frame-opcode-control /
                         frame-opcode-cont

frame-opcode-cont       = %x0 ; 幀繼續(xù)

frame-opcode-non-control= %x1 ; 文本幀
                        / %x2 ; 二進(jìn)制幀
                        / %x3-7
                        ; 4位長(zhǎng)度,保留用于未來(lái)的非控制幀

frame-opcode-control    = %x8 ; 連接關(guān)閉
                        / %x9 ; ping
                        / %xA ; pong
                        / %xB-F ; 保留用于未來(lái)的控制幀 
                       ; 4位長(zhǎng)度

frame-masked            = %x0
                        ; 幀沒(méi)有掩碼,沒(méi)有frame-masking-key
                        / %x1
                        ; 幀被掩碼,存在frame-masking-key 
                        ; 1位長(zhǎng)度

frame-payload-length    = ( %x00-7D )
                        / ( %x7E frame-payload-length-16 )
                        / ( %x7F frame-payload-length-63 )
                        ; 分別7, 7+16, or 7+64位長(zhǎng)度

frame-payload-length-16 = %x0000-FFFF ; 16位長(zhǎng)度

frame-payload-length-63 = %x0000000000000000-7FFFFFFFFFFFFFFF
                        ; 64位長(zhǎng)度

frame-masking-key       = 4( %x00-FF )
                          ; 僅當(dāng)frame-masked 是 1時(shí)存在
                          ; 32位長(zhǎng)度

frame-payload-data      = (frame-masked-extension-data
                           frame-masked-application-data)
                        ; 當(dāng)frame-masked是1
                          / (frame-unmasked-extension-data
                            frame-unmasked-application-data)
                        ; 當(dāng)frame-masked是0

frame-masked-extension-data     = *( %x00-FF )
                        ; 保留用于未來(lái)擴(kuò)展
                        ; n*8 位長(zhǎng)度,n >= 0

frame-masked-application-data   = *( %x00-FF )
                        ; n*8 位長(zhǎng)度,n >= 0

frame-unmasked-extension-data   = *( %x00-FF )
                        ; 保留用于未來(lái)擴(kuò)展
                        ; n*8 位長(zhǎng)度,n >= 0

frame-unmasked-application-data = *( %x00-FF )
                        ; n*8 位長(zhǎng)度,n >= 0

5.3.客戶(hù)端到服務(wù)器掩碼

一個(gè)掩碼的幀必須有5.2節(jié)定義的字段frame-masked設(shè)置為1。 掩碼鍵完全包含在幀中,5.2節(jié)定義的frame-masking-key。它用于掩碼定義在相同章節(jié)的frame-payload-data 中的“負(fù)載數(shù)據(jù)”,其包含“擴(kuò)展數(shù)據(jù)”和“應(yīng)用數(shù)據(jù)”。

掩碼鍵是由客戶(hù)端隨機(jī)選擇的32位值。當(dāng)準(zhǔn)備一個(gè)掩碼的幀時(shí),客戶(hù)端必須從允許的32位值集合中選擇一個(gè)新的掩碼鍵。掩碼鍵需要是不可預(yù)測(cè)的;因此,掩碼鍵必須來(lái)自一個(gè)強(qiáng)大的熵源,且用于給定幀的掩碼鍵必須不容易被服務(wù)器/代理預(yù)測(cè)用于后續(xù)幀的掩碼鍵。掩碼鍵的不可預(yù)測(cè)性對(duì)防止惡意應(yīng)用的作者選擇出現(xiàn)在報(bào)文上的字節(jié)是必要的。RFC 4086[RFC4086]討論了什么需要一個(gè)用于安全敏感應(yīng)用的合適的熵源。

掩碼不影響“負(fù)載數(shù)據(jù)”的長(zhǎng)度。變換掩碼數(shù)據(jù)到解掩碼數(shù)據(jù),或反之亦然,以下算法被應(yīng)用。相同的算法應(yīng)用,不管轉(zhuǎn)化的方向,例如,相同的步驟即應(yīng)用到掩碼數(shù)據(jù)也應(yīng)用到解掩碼數(shù)據(jù)。

變換數(shù)據(jù)的八位位組i ("transformed-octet-i")是原始數(shù)據(jù)的八位位組i("original-octet-i")異或(XOR)i取模4位置的掩碼鍵的八位位組("masking-key-octet-j"):

 j                   = i MOD 4
 transformed-octet-i = original-octet-i XOR masking-key-octet-j

負(fù)載長(zhǎng)度,在幀中以frame-payload-length表示,不包括掩碼鍵的長(zhǎng)度。它是“負(fù)載數(shù)據(jù)”的長(zhǎng)度,例如,跟在掩碼鍵后邊的字節(jié)數(shù)。

5.4.分片(Fragmentation)

分片的主要目的是允許當(dāng)消息開(kāi)始但不必緩沖該消息時(shí)發(fā)送一個(gè)未知大小的消息。如果消息不能被分片,那么端點(diǎn)將不得不緩沖整個(gè)消息以便在首字節(jié)發(fā)生之前統(tǒng)計(jì)出它的長(zhǎng)度。對(duì)于分片,服務(wù)器或中間件可以選擇一個(gè)合適大小的緩沖,當(dāng)緩沖滿(mǎn)時(shí),寫(xiě)一個(gè)片段到網(wǎng)絡(luò)。 第二個(gè)分片的用例是用于多路復(fù)用,一個(gè)邏輯通道上的一個(gè)大消息獨(dú)占輸出通道是不可取的,因此多路復(fù)用需要可以分割消息為更小的分段來(lái)更好的共享輸出通道。(注意,多路復(fù)用擴(kuò)展在本文檔中沒(méi)有描述)

除非另有擴(kuò)展指定,幀沒(méi)有語(yǔ)義含義。一個(gè)中間件可能合并且/或分割幀,如果客戶(hù)端和服務(wù)器沒(méi)有協(xié)商擴(kuò)展;或如果已協(xié)商了一些擴(kuò)展,但中間件理解所有協(xié)商的擴(kuò)展且知道如何去合并且/或分割在這些擴(kuò)展中存在的幀。這方面的一個(gè)含義是,在沒(méi)有擴(kuò)展情況下,發(fā)送者和接收者必須不依賴(lài)于特定幀邊界的存在。

以下規(guī)則應(yīng)用到分片:

  • 一個(gè)沒(méi)有分片的消息由單個(gè)帶有FIN位設(shè)置(5.2節(jié))和一個(gè)非0操作碼的幀組成。
  • 一個(gè)分片的消息由單個(gè)帶有FIN位清零(5.2節(jié))和一個(gè)非0操作碼的幀組成,跟隨零個(gè)或多個(gè)帶有FIN位清零和操作碼設(shè)置為0的幀,且終止于一個(gè)帶有FIN位設(shè)置且0操作碼的幀。一個(gè)分片的消息概念上是等價(jià)于單個(gè)大的消息,其負(fù)載是等價(jià)于按順序串聯(lián)片段的負(fù)載;然而,在存在擴(kuò)展的情況下,這個(gè)可能不適用擴(kuò)展定義的“擴(kuò)展數(shù)據(jù)”存在的解釋。例如,“擴(kuò)展數(shù)據(jù)”可能僅在首個(gè)片段開(kāi)始處存在且應(yīng)用到隨后的片段,或 “擴(kuò)展數(shù)據(jù)”可以存在于僅用于到特定片段的每個(gè)片段。在沒(méi)有“擴(kuò)展數(shù)據(jù)”的情況下,以下例子展示了分片如何工作。 例子:對(duì)于一個(gè)作為三個(gè)片段發(fā)送的文本消息,第一個(gè)片段將有一個(gè)0x1操作碼和一個(gè)FIN位清零,第二個(gè)片段將有一個(gè)0x0操作碼和一個(gè)FIN位清零,且第三個(gè)片段將有0x0操作碼和一個(gè)FIN位設(shè)置。

  • 控制幀(參見(jiàn)5.5節(jié))可能被注入到一個(gè)分片消息的中間。控制幀本身必須不被分割。

  • 消息分片必須按發(fā)送者發(fā)送順序交付給收件人。
  • 片段中的一個(gè)消息必須不能與片段中的另一個(gè)消息交替,除非已協(xié)商了一個(gè)能解釋交替的擴(kuò)展。
  • 一個(gè)端點(diǎn)必須能處理一個(gè)分片消息中間的控制幀。
  • 一個(gè)發(fā)送者可以位非控制消息創(chuàng)建任何大小的片段。
  • 客戶(hù)端和服務(wù)器必須支持接收分片和非分片的消息。
  • 由于控制幀不能被分片,一個(gè)中間件必須不嘗試改變控制幀的分片。
  • 如果使用了任何保留的位值且這些值的意思對(duì)中間件是未知的,一個(gè)中間件必須不改變一個(gè)消息的分片。
  • 在一個(gè)連接上下文中,已經(jīng)協(xié)商了擴(kuò)展且中間件不知道協(xié)商的擴(kuò)展的語(yǔ)義,一個(gè)中間件必須不改變?nèi)魏蜗⒌姆制M瑯?,沒(méi)有看見(jiàn)WebSocket握手(且沒(méi)被通知有關(guān)它的內(nèi)容)、導(dǎo)致一個(gè)WebSocket連接的一個(gè)中間件,必須不改變這個(gè)鏈接的任何消息的分片。
  • 由于這些規(guī)則,一個(gè)消息的所有分片是相同類(lèi)型,以第一個(gè)片段的操作碼設(shè)置。因?yàn)榭刂茙荒鼙环制糜谝粋€(gè)消息中的所有分片的類(lèi)型必須或者是文本、或者二進(jìn)制、或者一個(gè)保留的操作碼。

注意:如果控制幀不能被插入,一個(gè)ping延遲,例如,如果跟著一個(gè)大消息將是非常長(zhǎng)的。因此,要求在分片消息的中間處理控制幀。

實(shí)現(xiàn)注意:在沒(méi)有任何擴(kuò)展時(shí),一個(gè)接收者不必按順序緩沖整個(gè)幀來(lái)處理它。例如,如果使用了一個(gè)流式API,一個(gè)幀的一部分能被交付到應(yīng)用。但是,請(qǐng)注意這個(gè)假設(shè)可能不適用所有未來(lái)的WebSocket擴(kuò)展。

5.5.控制幀

控制幀由操作碼確定,其中操作碼最重要的位是1。當(dāng)前定義的用于控制幀的操作碼包括0x8 (Close)、0x9(Ping)、和0xA(Pong)。 操作碼0xB-0xF保留用于未來(lái)尚未定義的控制幀。

控制幀用于傳達(dá)有關(guān)WebSocket的狀態(tài)??刂茙梢圆迦氲椒制⒌闹虚g。

所有控制幀必須有一個(gè)125字節(jié)的負(fù)載長(zhǎng)度或更少, 必須不被分段。

5.5.1.Close

關(guān)閉(Close)幀包含0x8操作碼。

關(guān)閉幀可以包含內(nèi)容體(“幀的“應(yīng)用數(shù)據(jù)”部分)指示一個(gè)關(guān)閉的原因,例如端點(diǎn)關(guān)閉了、端點(diǎn)收到的幀太大、或端點(diǎn)收到的幀不符合端點(diǎn)期望的格式。如果有內(nèi)容體,內(nèi)容體的頭兩個(gè)字節(jié)必須是2字節(jié)的無(wú)符號(hào)整數(shù)(按網(wǎng)絡(luò)字節(jié)順序)代表一個(gè)在7.4節(jié)的/code/值定義的狀態(tài)碼。跟著2字節(jié)的整數(shù),內(nèi)容體可以包含UTF-8編碼的/reason/值,本規(guī)范沒(méi)有定義它的解釋。數(shù)據(jù)不必是人類(lèi)可讀的但可能對(duì)調(diào)試或傳遞打開(kāi)連接的腳本相關(guān)的信息是有用的。由于數(shù)據(jù)不保證人類(lèi)可讀,客戶(hù)端必須不把它顯示給最終用戶(hù)。

客戶(hù)端發(fā)送到服務(wù)器的關(guān)閉幀必須根據(jù)5.3節(jié)被掩碼。

在應(yīng)用發(fā)送關(guān)閉幀之后,必須不發(fā)送任何更多的數(shù)據(jù)幀。

如果一個(gè)端點(diǎn)接收到一個(gè)關(guān)閉幀且先前沒(méi)有發(fā)送一個(gè)關(guān)閉幀,端點(diǎn)必須在響應(yīng)中發(fā)送一個(gè)關(guān)閉幀。(當(dāng)在響應(yīng)中發(fā)生關(guān)閉幀時(shí),端點(diǎn)通常回送它接收到的狀態(tài)碼) 它應(yīng)該根據(jù)實(shí)際情況盡快這樣做。端點(diǎn)可以延遲發(fā)送關(guān)閉幀知道它當(dāng)前消息發(fā)送了(例如,如果一個(gè)分片消息的大多數(shù)已經(jīng)發(fā)送了,端點(diǎn)可以發(fā)送剩余的片段在發(fā)送一個(gè)關(guān)閉幀之前)。但是,不保證一個(gè)已經(jīng)發(fā)送關(guān)閉幀的端點(diǎn)將繼續(xù)處理數(shù)據(jù)。 發(fā)送并接收一個(gè)關(guān)閉消息后,一個(gè)端點(diǎn)認(rèn)為WebSocket連接關(guān)閉了且必須關(guān)閉底層的TCP連接。服務(wù)器必須立即關(guān)閉底層TCP連接,客戶(hù)端應(yīng)該等待服務(wù)器關(guān)閉連接但可能在發(fā)送和接收一個(gè)關(guān)閉消息之后的任何時(shí)候關(guān)閉連接,例如,如果它沒(méi)有在一個(gè)合理的時(shí)間周期內(nèi)接收到服務(wù)器的TCP關(guān)閉。

如果客戶(hù)端和服務(wù)器同時(shí)都發(fā)送了一個(gè)關(guān)閉消息,兩個(gè)端點(diǎn)都將發(fā)送和接收一個(gè)關(guān)閉消息且應(yīng)該認(rèn)為WebSocket連接關(guān)閉了并關(guān)閉底層TCP連接。

5.5.2. Ping

Ping幀包含0x9操作碼。

Ping幀可以包含“應(yīng)用數(shù)據(jù)”。

當(dāng)收到一個(gè)Ping幀時(shí),一個(gè)端點(diǎn)必須在響應(yīng)中發(fā)送一個(gè)Pong幀,除非它早已接收到一個(gè)關(guān)閉幀。它應(yīng)該盡可能快地以Pong幀響應(yīng)。Pong幀在5.5.3節(jié)討論。

一個(gè)端點(diǎn)可以在連接建立之后并在連接關(guān)閉之前的任何時(shí)候發(fā)送一個(gè)Ping幀。 注意:一個(gè)Ping即可以充當(dāng)一個(gè)keepalive,也可以作為驗(yàn)證遠(yuǎn)程端點(diǎn)仍可響應(yīng)的手段。

5.5.3. Pong

Pong幀包含一個(gè)0xA操作碼。

5.5.2節(jié)詳細(xì)說(shuō)明了應(yīng)用Ping和Pong幀的要求。

一個(gè)Pong幀在響應(yīng)中發(fā)送到一個(gè)Ping幀必須有在將回復(fù)的Ping幀的消息內(nèi)容體中發(fā)現(xiàn)的相同的“應(yīng)用數(shù)據(jù)”。

如果端點(diǎn)接收到一個(gè)Ping幀且尚未在響應(yīng)中發(fā)送Pong幀到之前的Ping幀,端點(diǎn)可以選擇僅為最近處理的Ping幀發(fā)送一個(gè)Pong幀。

一個(gè)Pong幀可以未經(jīng)請(qǐng)求的發(fā)送。這個(gè)充當(dāng)單向的心跳(heartbeat)。到未經(jīng)請(qǐng)求的Pong幀的一個(gè)響應(yīng)是不期望的。

5.6.數(shù)據(jù)幀

數(shù)據(jù)幀(例如,非控制幀)由操作碼最高位是0的操作碼標(biāo)識(shí)。當(dāng)前為數(shù)據(jù)幀定義的操作碼包括0x1(文本)、0x2(二進(jìn)制)。操作碼0x3-0x7保留用于未來(lái)尚未定義的非控制幀。

數(shù)據(jù)幀攜帶應(yīng)用層和/或擴(kuò)展層數(shù)據(jù)。操作碼決定了數(shù)據(jù)的解釋?zhuān)?/p>

Text

“負(fù)載數(shù)據(jù)”是編碼為UTF-8的文本數(shù)據(jù)。注意,一個(gè)特定的文本幀可能包括部分UTF-8序列;不管怎么樣,整個(gè)消息必須包含有效的UTF-8。重新組裝的消息中的無(wú)效的UTF-8的處理描述在8.1節(jié)。

Binary

“負(fù)載數(shù)據(jù)”是隨意的二進(jìn)制數(shù)據(jù),其解釋僅僅是在應(yīng)用層。

5.7.示例

  • 未掩碼文件消息的單個(gè)幀

    0x81 0x05 0x48 0x65 0x6c 0x6c 0x6f (包含 "Hello")

  • 掩碼的文本消息的單個(gè)幀

    0x81 0x85 0x37 0xfa 0x21 0x3d 0x7f 0x9f 0x4d 0x51 0x58 (包含 "Hello")

  • 一個(gè)分片的未掩碼的文本消息

    0x01 0x03 0x48 0x65 0x6c (包含 "Hel")

    0x80 0x02 0x6c 0x6f (包含 "lo")

  • 未掩碼的Ping請(qǐng)求和掩碼的Ping響應(yīng)

    0x89 0x05 0x48 0x65 0x6c 0x6c 0x6f

    (包含內(nèi)容體"Hello"、但內(nèi)容體的內(nèi)容是隨意的)

    0x8a 0x85 0x37 0xfa 0x21 0x3d 0x7f 0x9f 0x4d 0x51 0x58

    (包含內(nèi)容體"Hello"、匹配ping的內(nèi)容體)

  • 單個(gè)未掩碼幀中的256字節(jié)的二進(jìn)制消息

    0x82 0x7E 0x0100 [256字節(jié)的二進(jìn)制數(shù)據(jù)]

  • 單個(gè)未掩碼幀中的64KB的二進(jìn)制消息

    0x82 0x7F 0x0000000000010000 [65536字節(jié)的二進(jìn)制數(shù)據(jù)]

5.8.可擴(kuò)展性

協(xié)議被設(shè)計(jì)為允許擴(kuò)展,這將增加功能到基礎(chǔ)協(xié)議。端點(diǎn)的一個(gè)連接必須在打開(kāi)階段握手期間協(xié)商使用的任何擴(kuò)展。本規(guī)范提供了用于擴(kuò)展的操作碼0x3到0x7和0xB到0xF、“擴(kuò)展數(shù)據(jù)”字段、和幀-rsv1、幀rsv2、和幀rsv3幀頭位。9.1節(jié)進(jìn)一步討論了擴(kuò)展協(xié)商。以下是一些預(yù)期使用的擴(kuò)展。這個(gè)列表是不完整的也不規(guī)范的。

  • “擴(kuò)展數(shù)據(jù)”可以放置在“負(fù)載數(shù)據(jù)”中的“應(yīng)用數(shù)據(jù)”之前。
  • 保留的位可以分配給需要的每個(gè)幀。
  • 保留的操作碼值能被定義。
  • 如果需要更多的操作碼值,保留的位可以分配給操作碼字段。
  • 一個(gè)保留的位或一個(gè)“擴(kuò)展”操作碼可以定義以從“負(fù)載數(shù)據(jù)”中分配額外的位來(lái)定義更大的操作碼或更多的每幀位。
以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

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

編程獅公眾號(hào)