Websocket 協(xié)議格式說(shuō)明
最近整理項(xiàng)目中關(guān)于websocket中的部分砚嘴,由于之前代碼中websocket的功能不夠完整禾嫉,缺少了延續(xù)幀的數(shù)據(jù)拼接枚粘,以及mask的掩碼功能馅闽。所以初步深入了一下websocket協(xié)議。
關(guān)于websocket的數(shù)據(jù)幀格式馍迄,官方文檔提供了一個(gè)結(jié)構(gòu)圖
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:標(biāo)識(shí)該數(shù)據(jù)幀是否是信息的最后一幀數(shù)據(jù)福也,如果為1則表明距 上一次 FIN為1 的一幀之間,這些數(shù)據(jù)是完整的一條信息攀圈。
RSV 1-3:默認(rèn)為0暴凑,除非協(xié)商了擴(kuò)展定義了非0的意義。如果接收到非0赘来,且沒有協(xié)商擴(kuò)展现喳,接收端必須使WebSocket連接失敗凯傲。
-
Opcode:幀類型
0:Continuation Frame,表明該幀數(shù)據(jù)是一條完整信息的其中一幀
1:Text Frame 拿穴,這是一條文本數(shù)據(jù)
2:Binary Frame 泣洞,這是一條二進(jìn)制流數(shù)據(jù)
3 - 7:為以后的非控制幀保留
8:Connection Close Frame,這是關(guān)閉websocket連接請(qǐng)求的數(shù)據(jù)幀
9:Ping Frame 默色,這是一條ping幀
A:Pong Frame球凰,這是一條pong幀
B - F:為以后的控制幀保留
Mask:掩碼,是否加密數(shù)據(jù)腿宰,為1則需要對(duì)根據(jù)一個(gè)隨機(jī)的maskCode對(duì)數(shù)據(jù)進(jìn)行一次位運(yùn)算呕诉,一般客戶端發(fā)送給服務(wù)端的數(shù)據(jù)需要用掩碼加密,而服務(wù)端發(fā)給客戶端的一般不需要
-
Payload:盛放該幀數(shù)據(jù)的長(zhǎng)度吃度,由于該字段占據(jù)7bit甩挫,所以最大為127,所以規(guī)定
- 如果數(shù)據(jù)長(zhǎng)度<126椿每,則直接將數(shù)據(jù)長(zhǎng)度存在這7bit中
- 如果長(zhǎng)度=126伊者,則將數(shù)據(jù)長(zhǎng)度存在接下來(lái)的2字節(jié)數(shù)據(jù)中(2字節(jié)長(zhǎng)度可存最大無(wú)符號(hào)整數(shù)為 65535)
- 如果長(zhǎng)度=127,則將數(shù)據(jù)長(zhǎng)度存在接下來(lái)的8字節(jié)數(shù)據(jù)中
Extended payload length:接上個(gè)字段间护,這兩個(gè)字段用來(lái)存放數(shù)據(jù)的長(zhǎng)度
Masking-key:占據(jù) 0或4 Byte亦渗,上面的Mask字段為1,則需要生成4bit的隨機(jī)值汁尺,為0則為空
-
Payload data: (x + y)字節(jié)法精,存放了該數(shù)據(jù)幀所有的數(shù)據(jù)。由(Extension data + Application data 構(gòu)成)
- Extension data:x字節(jié)痴突,保留參數(shù)搂蜓,默認(rèn)為0 Byte,除非協(xié)商了擴(kuò)展辽装。
- Application data:y字節(jié)帮碰,如果上面Extension data為0,沒有協(xié)商拓展拾积,則此字段存儲(chǔ)了該幀所有的數(shù)據(jù)殉挽。
大小端
定義:對(duì)于一個(gè)由2個(gè)字節(jié)組成的16位整數(shù),在內(nèi)存中存儲(chǔ)這兩個(gè)字節(jié)有兩種方法
- 一種是將低序字節(jié)存儲(chǔ)在起始地址殷勘,這稱為小端(little-endian)字節(jié)序此再;
- 另一種方法是將高序字節(jié)存儲(chǔ)在起始地址,這稱為大端(big-endian)字節(jié)序玲销。
之所以關(guān)注這個(gè)問題是因?yàn)槭淠矗谕晟苿e人的Websocket協(xié)議時(shí),當(dāng)數(shù)據(jù)長(zhǎng)度大于125的時(shí)候贤斜,我需要將真正的數(shù)據(jù)長(zhǎng)度填充至2個(gè)字節(jié)或者8個(gè)字節(jié)的Extended payload length之中策吠,由于采用的小端模式存儲(chǔ)逛裤,導(dǎo)致服務(wù)端那邊讀取的數(shù)據(jù)長(zhǎng)度一直不對(duì),最后才發(fā)現(xiàn)是這個(gè)問題猴抹。
位運(yùn)算
&: 與 當(dāng)兩個(gè)位都為1時(shí)带族,結(jié)果才為1
1. 清零 與一個(gè)各位都為零的數(shù)值相與,結(jié)果為零
2. 取一個(gè)數(shù)的指定位, 用另一個(gè)指定位上全為1蟀给,其余位上全為0的數(shù)與該數(shù)相與蝙砌,則獲得的新值就是該數(shù)的指定位
3. 判斷奇偶 最未位為0則為偶數(shù),為1則為奇數(shù)
由此 可以用if ((a & 1) == 0)代替if (a % 2 == 0)來(lái)判斷a是不是偶數(shù)跋理,因?yàn)?br>
1的末位數(shù)為1
|: 或 當(dāng)兩個(gè)位都為0時(shí)择克,結(jié)果才為0
1. 對(duì)一個(gè)數(shù)的某些位設(shè)置為1, 用另一個(gè)指定位上全為1前普,其余位上全為0的數(shù)與該數(shù)相或肚邢,則獲得的新值指定位上的位就為1,非指定位還是會(huì)保持不變拭卿。
^: 異或 當(dāng)兩個(gè)位相同則為0骡湖,相異則為1
1. 翻轉(zhuǎn)指定位, 用另一個(gè)指定位上全為1峻厚,其余位上全為0的數(shù)與該數(shù)異或响蕴,則獲得的新值置頂位與該數(shù)指定位上的值正好相反
2. 與0相異或值不會(huì)改變 1000 0001 ^ 0000 0000 = 1000 0001
3. 交換兩個(gè)數(shù)
a = 1000 1001, b = 1101 0000
a ^= b; // a = 0101 1001
b ^= a; // b = 1000 1001
a ^= b; // a = 1101 0000
如上所示,a 與b進(jìn)行兩次異或后目木,得出的新值還是a换途。
~: 取反懊渡, 每一位上0 ——> 1, 1 ——> 0
該運(yùn)算符的優(yōu)先級(jí)比其他的要高刽射!
<< 左移運(yùn)算符 將一個(gè)數(shù)的二進(jìn)制位上各個(gè)位往左移若干位(左邊的位丟
棄,右邊補(bǔ)0)
a = 1011 1010, a<< 2 = 1110 1000
若左移時(shí)舍棄的高位不包含1剃执,則每左移一位誓禁,相當(dāng)于該數(shù)乘以2。
即 0011 1010<< 2 = 1110 1000
即 0011 1010 = 58肾档, 1110 1000 = 116
>> 右移運(yùn)算符 將一個(gè)數(shù)的二進(jìn)制位上各個(gè)位往右移若干位(右邊的位丟
棄摹恰,正數(shù)左邊補(bǔ)0,負(fù)數(shù)左邊補(bǔ)1)
a = 1011 1010, a>> 2 = 0010 1110
操作數(shù)每右移一位怒见,相當(dāng)于該數(shù)除以2俗慈。
即 1011 1010 = 186
即 0010 1110 = 46
不同長(zhǎng)度的數(shù)據(jù)進(jìn)行位運(yùn)算時(shí),則按照右端對(duì)齊遣耍,左端補(bǔ)齊0或者1闺阱,正數(shù)或者無(wú)符號(hào)數(shù)補(bǔ)0,負(fù)數(shù)補(bǔ)1
最后
??上篇文章立的flag這么快就被打臉了舵变,這是2021年的第一篇酣溃,也希望今年有一個(gè)好的開始吧瘦穆,再接再厲!