前言:
前段時間,在公司的專案中用到了WebSocket
,當時沒有時間好好整理。
最近,趁著有時間,就好好梳理了一下WebSocket
的相關知識。
本篇將介紹以下內容:
1、什麼是WebSocket
?
2、WebSocket
使用場景
3、WebSocket
底層原理(協議)
4、iOS
中WebSocket
的相關框架
一、什麼是 WebSocket ?
WebSocket = “HTTP第1次握手” + TCP
的“全雙工“通訊 的網路協議。
主要過程:
- 首先,通過
HTTP
第一次握手保證連線成功。 - 其次,再通過
TCP
實現瀏覽器與伺服器全雙工(full-duplex
)通訊。(通過不斷髮ping
包、pang
包保持心跳)
最終,使得 “服務端” 擁有 “主動” 發訊息給 “客戶端” 的能力。
這裡有幾個重點:
WebSocket
是基於TCP
的上部應用層網路協議。- 它依賴於
HTTP
的第一次握手成功 + 之後的TCP
雙向通訊。
二、WebSocket 應用場景
1. IM(即時通訊)
典型例子:微信、QQ等
當然,使用者量如果非常大的話,僅僅依靠WebSocket
肯定是不夠的,各大廠應該也有自己的一些優化的方案與措施。但對於使用者量不是很大的即時通訊需求,使用WebSocket
是一種不錯的方案。
2. 遊戲(多人對戰)
典型例子:王者榮耀等(應該都玩過)
3. 協同編輯(共享文件)
多人同時編輯同一份文件時,可以實時看到對方的操作。
這時,就用上了WebSocket
。
4. 直播/視訊聊天
對音訊/視訊需要較高的實時性。
5. 股票/基金等金融交易平臺
對於股票/基金的交易來說,每一秒的價格可能都會發生變化。
6. IoT(物聯網 / 智慧家居)
例如,我們的App需要實時的獲取智慧裝置的資料與狀態。
這時,就需要用到WebSocket
。
...... 等等等等
只要是一些對 “實時性” 要求比較高的需求,可能就會用到WebSocket
。
三、WebSocket 底層原理
WebSocket
是一個網路上的應用層協議,它依賴於HTTP
協議的第一次握手,握手成功後,資料就通過TCP/IP
協議傳輸了。
WebSocket
分為握手階段和資料傳輸階段,即進行了HTTP
一次握手 + 雙工的TCP
連線。
1、握手階段
首先,客戶端傳送訊息:
GET /chat HTTP/1.1
Host: server.qishare.org
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://qishare.org
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
事件
2、傳輸階段
WebSocket
是以 frame
的形式傳輸資料的。
比如會將一條訊息分為幾個frame
,按照先後順序傳輸出去。
這樣做會有幾個好處:
- 較大的資料可以分片傳輸,不用考慮到資料大小導致的長度標誌位不足夠的情況。
- 和
HTTP
的chunk
一樣,可以邊生成資料邊傳遞訊息,即提高傳輸效率。
WebSocket
傳輸過程使用的報文,如下所示:
具體的引數說明如下:
-
FIN(1 bit): 表示資訊的最後一幀,flag,也就是標記符。 PS:當然第一個訊息片斷也可能是最後的一個訊息片斷;
-
RSV1、RSV2、RSV3(均為1 bit): 預設均為0。如果有約定自定義協議則不為0,一般均為0。(協議擴充套件用)
-
Opcode(4 bit): 定義有效負載資料,如果收到了一個未知的操作碼,連線也必須斷掉,以下是定義的操作碼:
操作碼 | 含義 |
---|---|
%x0 | 連續訊息片斷 |
%x1 | 文字訊息片斷 |
%x2 | 二進位制訊息片斷 |
%x3-7 | (預留位)為將來的非控制訊息片斷保留的操作碼。 |
%x8 | 連線關閉 |
%x9 | 心跳檢查ping |
%xA | 心跳檢查pong |
%xB-F | (預留位)為將來的控制訊息片斷的保留操作碼。 |
-
Mask(1 bit): 是否傳輸資料新增掩碼。 若為1,掩碼必須放在masking-key區域。(後面會提到..) 注:客戶端給服務端發訊息
Mask
值均為1
。 -
Payload length: Payload欄位用來儲存傳輸資料的長度。
本身Payload報文欄位的大小可能有三種情況:7 bit
、7+16 bit
、7+64 bit
。
第一種:7 bit
,表示從0000000
~ 1111101
(即0
~125
),表示當前資料的length大小(較小資料,最大長度為125)。
第二種:(7+16) bit
:前7位為1111110(即126)
,126
代表後面會跟著2個位元組無符號數,用來儲存資料length大小(長度最小126,最大為65 535)。
第三種:(7+64) bit
:前7位為1111111(即127)
,127
代表後面會跟著8個位元組無符號數,用來儲存資料length大小(長度最小為65536,最大為2^16-1)。
Payload報文長度 | 所傳輸的資料大小區間 |
---|---|
7 bit | [ 0, 125] |
7 +16 bit | [ 126 , 65535] |
7 + 64 bit | [ 65536, 2^16 -1] |
說明:
傳輸資料的長度,以位元組的形式表示:7位、7+16位、或者7+64位。
1)如果這個值以位元組表示是0-125這個範圍,那這個值就表示傳輸資料的長度;
2)如果這個值是126,則隨後的2個位元組表示的是一個16進位制無符號數,用來表示傳輸資料的長度;
3)如果這個值是127,則隨後的是8個位元組表示的一個64位無符號數,這個數用來表示傳輸資料的長度。
- Masking-key(0 bit / 4 bit):
0 bit
:說明mask值不為1
,無掩碼。
4 bit
:說明mask值為1
,新增掩碼。
PS:客戶端傳送給服務端資料時,
mask
均為1。 同時,Masking-key
會儲存一個32位的掩碼。
-
Payload data(x+y byte): 負載資料為擴充套件資料及應用資料長度之和。
-
Extension data(x byte): 如果客戶端與服務端之間沒有特殊約定,那麼擴充套件資料的長度始終為0,任何的擴充套件都必須指定擴充套件資料的長度,或者長度的計算方式,以及在握手時如何確定正確的握手方式。如果存在擴充套件資料,則擴充套件資料就會包括在負載資料的長度之內。
-
Application data(y byte): 任意的應用資料,放在擴充套件資料之後。
應用資料的長度 = 負載資料的長度 - 擴充套件資料的長度
即:Application data = Payload data - Extension data
四、iOS 中 WebSocket 相關框架
WebSocket(iOS客戶端):
-
Starscream(swift): Websockets in swift for iOS and OSX.(
star 5k+
) -
SocketRocket(objective-c): A conforming Objective-C WebSocket client library.(
star:8k+
) -
SwiftWebSocket(swift): Fast Websockets in Swift for iOS and OSX.(
star:1k+
)
Socket(iOS客戶端):
-
CocoaAsyncSocket: Asynchronous socket networking library for Mac and iOS.(
star:11k+
) -
socket.io-client-swift: Socket.IO-client for iOS/OS X.(
star:4k+
)
下一篇,我們將用Starscream寫一個簡單的客戶端WebSocket Demo。
相關參考連結:
《微信,QQ這類IM app怎麼做——談談Websocket》(冰霜大佬)
《WebSocket的實現原理》 `
小編微信:可加並拉入《QiShare技術交流群》。
關注我們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公眾號)
推薦文章:
用 Swift 進行貝塞爾曲線繪製
Swift 5.1 (11) - 方法
Swift 5.1 (10) - 屬性
iOS App後臺保活
奇舞週刊