1. 程式人生 > >websocket協議的解析與實現(一)

websocket協議的解析與實現(一)

HTTP協議是短連線的,通訊模式如圖:

如何實現伺服器主動向客戶端傳送資料呢?!websocket協議就是解決這個問題的。

通訊過程大致如下:

本文中要有兩部分組成

一、建立連線請求過程

二、資料幀格式

一、建立連線請求過程

     在建立連線請求過程中使用的協議是HTTP協議。

1、客戶端傳送建立連線請求

      使用的是HTTP協議頭,伺服器端按照HTTP協議正常解析,但這塊不同的是伺服器程式必須判斷是否是websocket請求,其實伺服器只需要檢視該http協議頭中是否包含了websockt等字串,請求頭如下

websockt握手請求協議包含Upgrade: websocket欄位,伺服器通過該欄位就可以知道客戶端想要建立websockt連線請求。

2、伺服器響應連線請求

伺服器從請求協議包中獲取Sec-WebSocket-Key欄位值,如下圖:


然後將該key值與字串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”拼接形成新的字串,如"d359Fdo6omyqfxyYF7Yacw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11";然後伺服器對該字串進行SHA-1加密,之後再進行一次base64加密,將加密之後的結果作為最終的響應key傳送給客戶端,伺服器相依協議頭如下:

         其中Sec-WebSocket-Accept:欄位填充由請求中的Sec-WebSocket-Key欄位值與字串”258EAFA5-E914-47DA-95CA-C5AB0DC85B11“拼接而成的字串經過加密之後的字串組成。

按照以上兩步即可建立websocket連線。接下來客戶端與伺服器就可以互相非同步的傳送資料了。

二、資料幀格式

連線建立之後,客戶端與伺服器就可以相互發送資料了,資料包格式如下:


注意:

如果條件不滿足,則擴充套件位元組不出現在資料幀中。

列 明

位數

含義

取值

FIN

1 bit

是否是最後一幀資料

1表示後面沒資料了

0:表示後面還有資料

RSV

3 bit

保留

OPCODE

4 bit

訊息型別

0x0表示附加資料幀

0x1表示文字資料幀

0x2表示二進位制資料幀

0x3-7暫時無定義,為以後的非控制幀保留

0x8表示連線關閉

0x9表示

ping

0xA表示pong

0xB-F暫時無定義,為以後的控制幀保留

MASK

1 bit

是否經過掩碼處理;

客戶端必須對其傳送到伺服器的所有幀進行掩碼處理。

伺服器一旦收到無掩碼幀,將關閉連線。伺服器可能傳送一個狀態碼是1002(表示協議錯誤)的Close幀。

而伺服器傳送客戶端的資料幀不做掩碼處理,一旦客戶端發現經過掩碼處理的幀,將關閉連線。客戶端可能使用狀態碼1002

1:表示處理過 0:表示沒處理過

用於標識PayloadData是否經過掩碼處理。如果是1,Masking-key域的資料即是掩碼金鑰,用於解碼PayloadData。客戶端發出的資料幀需要進行掩碼處理,所以此位是1。

Payload length

7 bit

7+16bit

7+64 bit

PayloadData

資料長度

Payload長度是ExtensionData長度與ApplicationData長度之和

0-125:則是payload資料的真實長度

126:之後的2個位元組的16位無符號正數值表示真是長度

127之後的8個位元組形成的64位無符號整型數的值是payload的真實長度

(注意網路位元組序)

Masking-key

32 bit

掩碼

data

....

資料

.....................

1、客戶端到伺服器的資料必須通過掩碼處理

2、伺服器收到資料包之後需要判斷是否有掩碼,即MASK是否有效,無效則傳送關閉連線資料包,如果掩碼位有效,則解掩碼來獲取真正的資料

3、伺服器傳送給客戶端的資料不需要掩碼處理,相對簡單

協議示例:

客戶端傳送給伺服器的文字訊息”hello”

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

掩碼與解掩碼過程:

1)、計算j 

= i MOD 4

2)、計算掩碼後的資料,解掩碼方法相同 transformed-octet-i = original-octet-i XOR masking-key-octet-j

original-octet-i表示原始資料中下標為i的資料,如[0x7f 0x9f 0x4d 0x51 0x58]

masking-key-octet-j 表示四個位元組組成的掩碼陣列中下標為j的掩碼值,

[0x37 0xfa 0x21 0x3d ]

transformed-octet-i:表示掩碼或解掩碼之後的資料

示例解碼過程如下:

Unsigned char original-octet[] = {0x7f,0x9f,0x4d,0x51,0x58};

Unsigned char masking-key-octet[] = {0x37,0xfa,0x21,0x3d};

//LENGTH = sizeof(original-octet);

Unsigned char Transformed-octer[LENGTH];

0x7f:  i = 0;   =>    j = i % 4 = 0;

Transformed-octer[i] = original-octet[i] XOR masking-key-octet[j];

   = 0x7F XOR 0x37 = 0x48

        0x48 = ‘h’

其他數字掩碼或解掩碼過程同上

下一篇文章將給出伺服器和客戶端主要程式碼,伺服器是Linux下用C語言編寫的,客戶端使用js指令碼實現。