Websocket

Websocket協議

Websocket是html5提出的一個協議規範,參考rfc6455。

websocket約定了一個通信的規範,通過一個握手的機制,客戶端(瀏覽器)和服務器(webserver)之間能建立一個類似tcp的連接,從而方便c-s之間的通信。在websocket出現之前,web交互一般是基於http協議的短連接或者長連接。

WebSocket是爲解決客戶端與服務端實時通信而產生的技術。websocket協議本質上是一個基於tcp的協議,是先通過HTTP/HTTPS協議發起一條特殊的http請求進行握手後創建一個用於交換數據的TCP連接,此後服務端與客戶端通過此TCP連接進行實時通信。

Websocket和HTTP協議的關係

同樣作爲應用層的協議,WebSocket在現代的軟件開發中被越來越多的實踐,和HTTP有很多相似的地方,這裏將它們簡單的做一個純個人、非權威的比較:

相同點

  1. 都是基於TCP的應用層協議。
  2. 都使用Request/Response模型進行連接的建立。
  3. 在連接的建立過程中對錯誤的處理方式相同,在這個階段WS可能返回和HTTP相同的返回碼。
  4. 都可以在網絡中傳輸數據。

不同點

  1. WS使用HTTP來建立連接,但是定義了一系列新的header域,這些域在HTTP中並不會使用。
  2. WS的連接不能通過中間人來轉發,它必須是一個直接連接。
  3. WS連接建立之後,通信雙方都可以在任何時刻向另一方發送數據。
  4. WS連接建立之後,數據的傳輸使用幀來傳遞,不再需要Request消息。
  5. WS的數據幀有序。

協議

1. 握手

客戶端發起握手。

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com 
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

從上面的協議中可以看到websocket基於HTTP協議的GET。而且只支持GET.

Upgrade:upgrade是HTTP1.1中用於定義轉換協議的header域。它表示,如果服務器支持的話,客戶端希望使用現有的「網絡層」已經建立好的這個「連接(此處是TCP連接)」,切換到另外一個「應用層」(此處是WebSocket)協議。

Connection:HTTP1.1中規定Upgrade只能應用在「直接連接」中,所以帶有Upgrade頭的HTTP1.1消息必須含有Connection頭,因爲Connection頭的意義就是,任何接收到此消息的人(往往是代理服務器)都要在轉發此消息之前處理掉Connection中指定的域(不轉發Upgrade域)。

Sec-WebSocket-*:第7行標識了客戶端支持的子協議的列表(關於子協議會在下面介紹),第8行標識了客戶端支持的WS協議的版本列表,第5行用來發送給服務器使用(服務器會使用此字段組裝成另一個key值放在握手返回信息裏發送客戶端)。

服務端響應

HTTP/1.1 101 Switching Protocols
Content-Length: 0
Upgrade: websocket
Sec-Websocket-Accept: ZEs+c+VBk8Aj01+wJGN7Y15796g=
Server: TornadoServer/4.5.1
Connection: Upgrade
Date: Wed, 21 Jun 2017 03:29:14 GMT

Sec-Websocket-Accept 是一個校驗。用客戶端發來的sec_key 服務器通過sha1計算拼接商GUID【258EAFA5-E914-47DA-95CA-C5AB0DC85B11 】 。然後再base64encode

數據傳輸

客戶端和服務器連接成功後,就可以進行通信了,通信協議格式是WebSocket格式,服務器端採用Tcp Socket方式接收數據,進行解析,協議格式如下:

img

這裏使用的是數據存儲的位(bit),當進行加密的時候,最終要的一位就是最左邊的第一個。

  • FIN :1bit ,表示是消息的最後一幀,如果消息只有一幀那麼第一幀也就是最後一幀。

  • RSV1,RSV2,RSV3:每個1bit,必須是0,除非擴展定義爲非零。如果接受到的是非零值但是擴展沒有定義,則需要關閉連接。

  • Opcode:4bit,解釋Payload數據,規定有以下不同的狀態,如果是未知的,接收方必須馬上關閉連接。狀態如下:0x0(附加數據幀) 0x1(文本數據幀) 0x2(二進制數據幀) 0x3-7(保留爲之後非控制幀使用) 0xB-F(保留爲後面的控制幀使用) 0x8(關閉連接幀) 0x9(ping) 0xA(pong)

  • Mask:1bit,掩碼,定義payload數據是否進行了掩碼處理,如果是1表示進行了掩碼處理。

    Masking-key域的數據即是掩碼密鑰,用於解碼PayloadData。客戶端發出的數據幀需要進行掩碼處理,所以此位是1。
    
  • Payload length:7位,7 + 16位,7+64位,payload數據的長度,如果是0-125,就是真實的payload長度,如果是126,那麼接着後面的2個字節對應的16位無符號整數就是payload數據長度;如果是127,那麼接着後面的8個字節對應的64位無符號整數就是payload數據的長度。

  • Masking-key:0到4字節,如果MASK位設爲1則有4個字節的掩碼解密密鑰,否則就沒有。

  • Payload data:任意長度數據。包含有擴展定義數據和應用數據,如果沒有定義擴展則沒有此項,僅含有應用數據。

客戶端

var websocket = new WebSocket("ws://127.0.0.1")
websocket.onopen = function(){

}

websocket.onmessage = function(){}

websocket.onclose = function(){}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章