
Websocket是應用層第七層上的一個應用層協定,它必須依賴 HTTP 協定進行一次握手 ,握手成功後,資料就直接從 TCP 通道傳輸,與 HTTP 無關了。即:websocket分為握手和資料傳輸階段,即進行了HTTP握手 + 雙工的TCP連接配接。
1.介紹一下websocket和通信過程?
1.1 基本概念
[!NOTE]
1.2 通信過程
下面我們分别來看一下這兩個階段的具體實作原理:
1.2.1 握手階段
用戶端發送消息:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Version: 13
服務端傳回消息:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
這裡值得注意的是Sec-WebSocket-Accept的計算方法:
base64(hsa1(sec-websocket-key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11))
如果這個Sec-WebSocket-Accept計算錯誤浏覽器會提示:Sec-WebSocket-Accept dismatch
如果傳回成功,Websocket就會回調onopen事件
1.2.2 傳輸階段
Websocket的資料傳輸是frame形式傳輸的,比如會将一條消息分為幾個frame,按照先後順序傳輸出去。
這樣做會有幾個好處:
- a、大資料的傳輸可以分片傳輸,不用考慮到資料大小導緻的長度标志位不足夠的情況。
- b、和http的chunk一樣,可以邊生成資料邊傳遞消息,即提高傳輸效率。
websocket傳輸使用的協定參數說明如下:
FIN:1位,用來表明這是一個消息的最後的消息片斷,當然第一個消息片斷也可能是最後的一個消息片斷;
RSV1, RSV2, RSV3: 分别都是1位,如果雙方之間沒有約定自定義協定,那麼這幾位的值都必須為0,否則必須斷掉WebSocket連接配接;
Opcode: 4位操作碼,定義有效負載資料,如果收到了一個未知的操作碼,連接配接也必須斷掉,以下是定義的操作碼:
- %x0 表示連續消息片斷
- %x1 表示文本消息片斷
- %x2 表未二進制消息片斷
- %x3-7 為将來的非控制消息片斷保留的操作碼
- %x8 表示連接配接關閉
- %x9 表示心跳檢查的ping
- %xA 表示心跳檢查的pong
- %xB-F 為将來的控制消息片斷的保留操作碼
- Mask: 1位,定義傳輸的資料是否有加掩碼,如果設定為1,掩碼鍵必須放在masking-key區域,用戶端發送給服務端的所有消息,此位的值都是1;
- Payload length: 傳輸資料的長度,以位元組的形式表示:7位、7+16位、或者7+64位。如果這個值以位元組表示是0-125這個範圍,那這個值就表示傳輸資料的長度;如果這個值是126,則随後的兩個位元組表示的是一個16進制無符号數,用來表示傳輸資料的長度;如果這個值是127,則随後的是8個位元組表示的一個64位無符合數,這個數用來表示傳輸資料的長度。多位元組長度的數量是以網絡位元組的順序表示。負載資料的長度為擴充資料及應用資料之和,擴充資料的長度可能為0,因而此時負載資料的長度就為應用資料的長度。
- Masking-key: 0或4個位元組,用戶端發送給服務端的資料,都是通過内嵌的一個32位值作為掩碼的;掩碼鍵隻有在掩碼位設定為1的時候存在。
- Payload data: (x+y)位,負載資料為擴充資料及應用資料長度之和。
- Extension data: x位,如果用戶端與服務端之間沒有特殊約定,那麼擴充資料的長度始終為0,任何的擴充都必須指定擴充資料的長度,或者長度的計算方式,以及在握手時如何确定正确的握手方式。如果存在擴充資料,則擴充資料就會包括在負載資料的長度之内。
- Application data: y位,任意的應用資料,放在擴充資料之後,應用資料的長度=負載資料的長度-擴充資料的長度。
2. Websocket傳輸檔案的思路?(加分項)
- 伺服器端偵聽某端口,接受WebSocket請求,後面可用nginx作反向代理,外部看到的将是80端口
- 用戶端連接配接伺服器的WebSocket位址,連接配接成功後,首先傳送一個NEW_FILE的資料包,裡面帶上要傳輸的檔案名
- 伺服器端收到NEW_FILE包後,解析出檔案名,并建立目标檔案,再回複ACK_NEW_FILE的資料包
- 用戶端收到ACK_NEW_FILE的資料包後,檢查回應的code,如是成功碼,則啟動一個線程,該線程負責将源檔案的資料封裝成多個FILE_DATA資料包,傳送這些FILE_DATA資料至伺服器端
- 伺服器端接收FILE_DATA資料包,解析出裡面的檔案資料,将檔案資料寫入檔案
- 用戶端發送完源檔案資料後,再傳送一個FILE_END資料包,該檔案包中帶上源檔案的MD5值
- 伺服器端收到FILE_END資料包後,比對源檔案的MD5值與目标檔案的MD5值,如相同,則認為傳輸成功,并傳回ACK_FILE_END資料包,裡面帶上成功碼
- 用戶端收到ACK_FILE_END資料包,檢查回應的code,如是成功碼,則認為傳輸成功,否則認為傳輸失敗
3. Websocket是什麼樣的協定,具體有什麼優點?
3.1 基本介紹
- 首先,Websocket是一個持久化的協定,相對于HTTP這種非持久的協定來說。簡單的舉個例子吧,用目前應用比較廣泛的PHP生命周期來解釋。
- HTTP的生命周期通過 Request 來界定,也就是一個 Request 一個 Response ,那麼在 HTTP1.0 中,這次HTTP請求就結束了。
- 在HTTP1.1中進行了改進,使得有一個keep-alive,也就是說,在一個HTTP連接配接中,可以發送多個Request,接收多個Response。但是請記住 Request = Response , 在HTTP中永遠是這樣,也就是說一個request隻能有一個response。而且這個response也是被動的,不能主動發起。
- Websocket是基于HTTP協定的,或者說借用了HTTP的協定來完成一部分握手。
3.2 細節介紹
首先我們來看個典型的 Websocket 握手(借用Wikipedia的。。)
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
熟悉HTTP的童鞋可能發現了,這段類似HTTP協定的握手請求中,多了幾個東西。我會順便講解下作用。
Upgrade: websocket
Connection: Upgrade
這個就是Websocket的核心了,告訴 Apache 、 Nginx 等伺服器:注意啦,我發起的是Websocket協定,快點幫我找到對應的助理處理~不是那個老土的HTTP。
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
首先, Sec-WebSocket-Key 是一個 Base64 encode 的值,這個是浏覽器随機生成的,告訴伺服器:泥煤,不要忽悠窩,我要驗證尼是不是真的是Websocket助理。
然後, Sec_WebSocket-Protocol 是一個使用者定義的字元串,用來區分同URL下,不同的服務所需要的協定。簡單了解:今晚我要服務A,别搞錯啦~
最後, Sec-WebSocket-Version 是告訴伺服器所使用的 Websocket Draft(協定版本),在最初的時候,Websocket協定還在 Draft 階段,各種奇奇怪怪的協定都有,而且還有很多期奇奇怪怪不同的東西,什麼Firefox和Chrome用的不是一個版本之類的,當初Websocket協定太多可是一個大難題。。不過現在還好,已經定下來啦大家都使用的一個東西 脫水: 服務員,我要的是13歲的噢→_→
然後伺服器會傳回下列東西,表示已經接受到請求, 成
功建立Websocket啦!
HTTP/1.1 101 Switching Protocols
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
這裡開始就是HTTP最後負責的區域了,告訴客戶,我已經成功切換協定啦~
依然是固定的,告訴用戶端即将更新的是 Websocket 協定,而不是mozillasocket,lurnarsocket或者shitsocket。
然後, Sec-WebSocket-Accept 這個則是經過伺服器确認,并且加密過後的 Sec-WebSocket-Key 。 伺服器:好啦好啦,知道啦,給你看我的ID CARD來證明行了吧。。
後面的, Sec-WebSocket-Protocol 則是表示最終使用的協定。
至此,HTTP已經完成它所有工作了,接下來就是完全按照Websocket協定進行了。具體的協定就不在這闡述了。