WebSocket(2) 數(shù)據(jù)封裝和傳輸

Websocket數(shù)據(jù)幀的封裝和傳輸其實(shí)和處理握手請(qǐng)求的流程差不太多,都需要通過(guò)bytebuffer寫(xiě)入Socket的輸出流或者從輸入流讀取。

數(shù)據(jù)幀格式

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 ...                |
 +---------------------------------------------------------------+
 
 具體每一bit的意思
FIN      1bit 表示信息的最后一幀
RSV 1-3  1bit each 以后備用的 默認(rèn)都為 0
Opcode   4bit 幀類(lèi)型,稍后細(xì)說(shuō)
Mask     1bit 掩碼海渊,是否加密數(shù)據(jù),默認(rèn)必須置為1
Payload len  7bit 數(shù)據(jù)的長(zhǎng)度
Masking-key      1 or 4 bit 掩碼
Payload data     (x + y) bytes 數(shù)據(jù)
Extension data   x bytes  擴(kuò)展數(shù)據(jù)
Application data y bytes  程序數(shù)據(jù)


這個(gè)看著比較蛋疼的一點(diǎn)是頂部用的十進(jìn)制而不是八進(jìn)制,仔細(xì)看一下每行有4個(gè)字節(jié)

Fin為1表示是最后一個(gè)一個(gè)數(shù)據(jù)幀贮乳,有時(shí)候數(shù)據(jù)需要分成多個(gè)數(shù)據(jù)包來(lái)發(fā)送,這就需要用到分片胀屿,也就是使用多個(gè)數(shù)據(jù)幀來(lái)傳輸一個(gè)數(shù)據(jù)塘揣。

Opcode表示幀的類(lèi)型,例如這個(gè)傳輸?shù)膸俏谋绢?lèi)型還是二進(jìn)制類(lèi)型宿崭,二進(jìn)制類(lèi)型傳輸?shù)臄?shù)據(jù)可以是圖片或者語(yǔ)音之類(lèi)的亲铡。

OPCODE:4位
解釋PayloadData,如果接收到未知的opcode葡兑,接收端必須關(guān)閉連接奖蔓。
0x0表示附加數(shù)據(jù)幀
0x1表示文本數(shù)據(jù)幀
0x2表示二進(jìn)制數(shù)據(jù)幀
0x3-7暫時(shí)無(wú)定義,為以后的非控制幀保留
0x8表示連接關(guān)閉
0x9表示ping
0xA表示pong
0xB-F暫時(shí)無(wú)定義讹堤,為以后的控制幀保留

Mask表示是否經(jīng)過(guò)掩碼處理

Payload len占據(jù)七位用來(lái)描述消息長(zhǎng)度吆鹤,由于7位最多只能描述127所以這個(gè)值會(huì)代表三種情況,一種是消息內(nèi)容少于126存儲(chǔ)消息長(zhǎng)度,如果消息長(zhǎng)度少于UINT16的情況此值為126,當(dāng)消息長(zhǎng)度大于UINT16的情況下此值為127;這兩種情況的消息長(zhǎng)度存儲(chǔ)到緊隨后面的byte[],分別是UINT16(2位byte)和UINT64(4位byte)。

客戶(hù)端到服務(wù)器端掩碼處理

客戶(hù)端發(fā)送到服務(wù)器端的數(shù)據(jù)必須進(jìn)行掩碼處理洲守,掩碼的密鑰是一個(gè)32位的隨機(jī)值疑务。所有數(shù)據(jù)都需要與掩碼做一次異或運(yùn)算沾凄。

j = i mod 4(i 是傳輸數(shù)據(jù)中的十進(jìn)制的索引下標(biāo))
轉(zhuǎn)換后的數(shù)據(jù) d = original  ^ mask[j]

消息分片

分片的目的是允許發(fā)送未知長(zhǎng)度的消息。如果消息不能被碎片化知允,那么一端就必須將消息整個(gè)地載入內(nèi)存緩沖撒蟀,計(jì)算長(zhǎng)度,構(gòu)建frame并發(fā)送温鸽。有了碎片化的機(jī)制保屯,服務(wù)端或者中間件就可以選取適用的內(nèi)存緩沖長(zhǎng)度,然后當(dāng)緩沖滿(mǎn)了之后就發(fā)送一個(gè)消息碎片涤垫。

分片規(guī)則:

  • 一個(gè)未分片的消息只有一幀(FIN為1姑尺,opcode非0)
  • 一個(gè)分片的消息由起始幀(FIN為0,opcode非0)蝠猬,若干(0個(gè)或多個(gè))幀(FIN為0切蟋,opcode為0),結(jié)束幀(FIN為1吱雏,opcode為0)敦姻。
  • 控制幀可以出現(xiàn)在分片消息中間,但控制幀本身不允許分片歧杏×耄控制幀是通過(guò)它的 opcode 的最高有效位是 1 去確定的。當(dāng)前已經(jīng)定義了的控制幀包括 0x8 (close)犬绒,0x9 (Ping)旺入,0xA (Pong)。
  • 消息幀必須以其被發(fā)送時(shí)的順序傳遞到接收端凯力。
  • 組成消息的所有幀都是相同的數(shù)據(jù)類(lèi)型茵瘾,在第一個(gè)幀中的 opcode 中指明。因?yàn)榭刂茙荒鼙凰槠篮祝M成消息的碎片類(lèi)型必須是文本拗秘、二進(jìn)制、或者其他的保留類(lèi)型祈惶。

未分片的消息

FIN=0,Opcode>0

分片的消息分片可以分為三個(gè)類(lèi)型:

開(kāi)始幀:FIN=0,Opcode>0;一個(gè)  
傳輸幀:FIN=0,Opcode=0;零個(gè)或多個(gè)
終止幀:FIN=1,Opcode=0;一個(gè)

例子解析

比如我們接受到了一段消息的數(shù)據(jù)部分是810548656c6c6f

81 05:  10000001 00000101 
48 65:  01001000 01100101
6c 6c:  01001100 01001100
6f   :  01001111 



0:1雕旨,這是最后一幀 
1~3:全為0 
4~7:0001,文本數(shù)據(jù)幀
8:0捧请,PlayloadData未經(jīng)過(guò)掩碼 
9~15:0000101 = 5 < 125凡涩,因此數(shù)據(jù)長(zhǎng)度位5
剩下的:48 65 6c 6c 6f即為Hello

比如我們發(fā)送的消息123456789數(shù)據(jù)部分是818911eb9db220d9ae8624ddaa8a28

81 89 : 10000001 10001001 
11 eb : 00010001 11101011
9d b2 : 10011101 10110010
20 d9 : 00100000 11011001
ae 86 : 10101110 10000110
24 dd : 00100100 11011101
aa 8a : 10101010 10001010
28    : 00101000


0:1,這是最后一幀 
1~3:全為0 
4~7:0001疹蛉,文本數(shù)據(jù)幀
8:1活箕,PlayloadData經(jīng)過(guò)掩碼,(所有的由客戶(hù)端發(fā)往服務(wù)端的幀此數(shù)位都被設(shè)置成 1可款。) 
9~15:0001001 = 9 < 125育韩,因此數(shù)據(jù)長(zhǎng)度位9 
11 eb 9d b2:掩碼 
20 d9 ae 86 24 dd aa 8a 28:數(shù)據(jù) 

下面演示消息123456789怎么通過(guò)掩碼加密成20 d9 ae 86 24 dd aa 8a 28

1           2        3            發(fā)送的消息
31          32       33           消息對(duì)應(yīng)的ASCII
00110001 00110010 00110011        


11          eb       9d           掩碼
00010001 11101011 10011101


交配
00110001 00110010 00110011 

00010001 11101011 10011101 

00100000 11011001 10101110

20          d9       ae





關(guān)閉幀

前面提到了關(guān)閉幀的操作碼opcode是0x8
關(guān)閉幀也可以包含消息體克蚂,通過(guò)數(shù)據(jù)幀的“應(yīng)用數(shù)據(jù)部分表示關(guān)閉原因”,消息體的前兩個(gè)字節(jié)必須是無(wú)符號(hào)的整型數(shù)(采用網(wǎng)絡(luò)字節(jié)序)座慰,以此整型數(shù)去表示狀態(tài)碼陨舱。在兩個(gè)字節(jié)的無(wú)符號(hào)整型數(shù)之后翠拣,可以跟上以 UTF-8 編碼的數(shù)據(jù)表示 /reason/版仔,/reason/ 數(shù)據(jù)的具體解釋方式此文檔并沒(méi)有定義。并且 /reason/ 的內(nèi)容不一定是人類(lèi)可讀的數(shù)據(jù)误墓,只要是有利于發(fā)起連接的腳本進(jìn)行調(diào)試就可以蛮粮。因?yàn)?/reason/ 并不一定就是人類(lèi)可讀的,所以客戶(hù)端必須不將此內(nèi)容展示給最終用戶(hù)谜慌。

應(yīng)用程序在發(fā)送了關(guān)閉幀之后就不可以再發(fā)送其他數(shù)據(jù)幀了然想。

如果接收到關(guān)閉幀的一端之前沒(méi)有發(fā)送過(guò)關(guān)閉幀的話(huà),那么它必須發(fā)送一個(gè)關(guān)閉幀作為響應(yīng)欣范。(當(dāng)發(fā)送一個(gè)關(guān)閉幀作為響應(yīng)的時(shí)候变泄,發(fā)送端通常在作為響應(yīng)的關(guān)閉幀中采用和其接收到的關(guān)閉幀相同的狀態(tài)碼)。并且響應(yīng)必須盡快的發(fā)送恼琼。一端可以延遲關(guān)閉幀的發(fā)送妨蛹,比如一個(gè)重要的消息已經(jīng)發(fā)送了一半,那么可以在消息的剩余部分發(fā)送完之后再發(fā)送關(guān)閉幀晴竞。但是作為首先發(fā)送了關(guān)閉幀蛙卤,并在等待另一端進(jìn)行關(guān)閉響應(yīng)的那一端來(lái)說(shuō),并不一定保證其會(huì)繼續(xù)處理數(shù)據(jù)內(nèi)容噩死。

在發(fā)送和接收到了關(guān)閉幀之后颤难,一端就可以認(rèn)為 WebSocket 連接已經(jīng)關(guān)閉,并且必須關(guān)閉底層相關(guān)的 TCP 連接已维。如果是服務(wù)端首先發(fā)送了關(guān)閉幀行嗤,那么在接收到客戶(hù)端返回的關(guān)閉幀之后,服務(wù)端必須立即關(guān)閉底層相關(guān)的 TCP 連接垛耳;但是如果是客戶(hù)端首先發(fā)送了關(guān)閉幀栅屏,并接收到了服務(wù)端返回的關(guān)閉幀之后,可以選擇其認(rèn)為合適的時(shí)間關(guān)閉連接艾扮,比如既琴,在一段時(shí)間內(nèi)沒(méi)有接收到服務(wù)端的 TCP 關(guān)閉握手。

如果客戶(hù)端和服務(wù)端同時(shí)發(fā)送了關(guān)閉消息泡嘴,那么它們兩端都將會(huì)接收到來(lái)自對(duì)方的關(guān)閉消息甫恩,那么它們就可以認(rèn)為 WebSocket 連接已經(jīng)關(guān)閉,并且關(guān)閉底層相關(guān)的 TCP 連接酌予。

已經(jīng)定義的狀態(tài)碼
1000 表明這是一個(gè)正常的關(guān)閉
1001 表明一端是即將關(guān)閉的磺箕,比如服務(wù)端將關(guān)閉或者瀏覽器跳轉(zhuǎn)到了其他頁(yè)面
1002 表明一端正在因?yàn)閰f(xié)議錯(cuò)誤而關(guān)閉連接
1003 表明一端因?yàn)榻邮盏搅藷o(wú)法受理的數(shù)據(jù)而關(guān)閉連接(比如只能處理文本的一端接收到了一個(gè)二進(jìn)制的消息)
1004 保留的奖慌。
1005 是一個(gè)保留值,并且必須不可以作為關(guān)閉幀的狀態(tài)碼
1006 是一個(gè)保留值松靡,并且必須不可以作為關(guān)閉幀的狀態(tài)碼
1007 表明一端接收到的消息內(nèi)容與之標(biāo)記的類(lèi)型不符而需要關(guān)閉連接(比如文本消息中出現(xiàn)了非 UTF-8 的內(nèi)容)
1008 表明了一端接收到的消息內(nèi)容違反了其接收消息的策略而需要關(guān)閉連接
1009 表明一端接收了非常大的數(shù)據(jù)而其無(wú)法處理時(shí)需要關(guān)閉連接
1010 表明了客戶(hù)端希望服務(wù)端協(xié)商一個(gè)或多個(gè)擴(kuò)展简僧,但是服務(wù)端在返回的握手信息中包含協(xié)商信息
1011 表明了一端遇到了異常情況使得其無(wú)法完成請(qǐng)求而需要關(guān)閉連接
1015 是一個(gè)保留值,并且必須不可以作為關(guān)閉幀的狀態(tài)碼


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雕欺,一起剝皮案震驚了整個(gè)濱河市岛马,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌屠列,老刑警劉巖啦逆,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異笛洛,居然都是意外死亡夏志,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)苛让,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)沟蔑,“玉大人,你說(shuō)我怎么就攤上這事狱杰∈莶模” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵浦旱,是天一觀的道長(zhǎng)宇色。 經(jīng)常有香客問(wèn)我,道長(zhǎng)颁湖,這世上最難降的妖魔是什么宣蠕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮甥捺,結(jié)果婚禮上抢蚀,老公的妹妹穿的比我還像新娘。我一直安慰自己镰禾,他們只是感情好皿曲,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著吴侦,像睡著了一般屋休。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上备韧,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天劫樟,我揣著相機(jī)與錄音,去河邊找鬼。 笑死叠艳,一個(gè)胖子當(dāng)著我的面吹牛奶陈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播附较,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼吃粒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了拒课?” 一聲冷哼從身側(cè)響起徐勃,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捕发,沒(méi)想到半個(gè)月后疏旨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扎酷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了遏匆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片法挨。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖幅聘,靈堂內(nèi)的尸體忽然破棺而出凡纳,到底是詐尸還是另有隱情,我是刑警寧澤帝蒿,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布荐糜,位于F島的核電站,受9級(jí)特大地震影響葛超,放射性物質(zhì)發(fā)生泄漏暴氏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一绣张、第九天 我趴在偏房一處隱蔽的房頂上張望答渔。 院中可真熱鬧,春花似錦侥涵、人聲如沸沼撕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)务豺。三九已至,卻和暖如春嗦明,著一層夾襖步出監(jiān)牢的瞬間笼沥,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留敬拓,地道東北人邻薯。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像乘凸,于是被迫代替她去往敵國(guó)和親厕诡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一营勤、內(nèi)容概覽 WebSocket的出現(xiàn)灵嫌,使得瀏覽器具備了實(shí)時(shí)雙向通信的能力。本文由淺入深葛作,介紹了WebSocket...
    Calvin李閱讀 2,522評(píng)論 2 10
  • 1 述 WebSocket是一種網(wǎng)絡(luò)通信協(xié)議WebSocket 協(xié)議在2008年誕生寿羞,2011年成為國(guó)際標(biāo)準(zhǔn)。HT...
    凱玲之戀閱讀 680評(píng)論 0 0
  • 首先一定要明確,排線(xiàn)條沒(méi)有固定的方式虱岂,愛(ài)怎么排怎么排玖院,達(dá)到效果就好。 若是畫(huà)個(gè)畫(huà)還要規(guī)定畫(huà)線(xiàn)條的方式第岖,那也太可怕了...
    何天衢繪畫(huà)老師閱讀 11,530評(píng)論 18 160
  • luck小諾星閱讀 228評(píng)論 0 0
  • 金秋十月难菌,天高氣爽;碩果累累蔑滓,十里飄香郊酒;佳偶成配,禮鳴樂(lè)奏键袱,喜氣洋洋燎窘,空氣中到處彌漫著禮炮的煙味兒和酒席的噴香誘人...
    蘭小七閱讀 307評(píng)論 0 0