WebSocketWebSocket
WebSocketWebSocketWebSocketiOSWebSocketStarscreamSwiftGolang
一、什么是 WebSocket ?
TCP
主要过程:
HTTPTCPfull-duplexpingpang
最终,使得 “服务端” 拥有 “主动” 发消息给 “客户端” 的能力。
这里有几个重点:
WebSocketTCPHTTPTCP
二、WebSocket 应用场景
1. IM(即时通讯)
WebSocketWebSocket
2. 游戏(多人对战)
典型例子:王者荣耀等(应该都玩过)
3. 协同编辑(共享文档)
WebSocket
4. 直播/视频聊天
对音频/视频需要较高的实时性。
5. 股票/基金等金融交易平台
对于股票/基金的交易来说,每一秒的价格可能都会发生变化。
6. IoT(物联网 / 智能家居)
WebSocket
......
等等等等
WebSocket
三、WebSocket 底层原理
WebSocketHTTPTCP/IP
WebSocketHTTPTCP
1、握手阶段
Golang
GET /chat HTTP/1.1
Host: 127.0.0.1:8000
Origin: ws://127.0.0.1:8000
Qi-WebSocket-Version: 0.0.1
Sec-WebSocket-Version: 13
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: aGFjb2hlYW9rd2JtdmV5eA==
swift
"Upgrade": "websocket",
"Connection": "Upgrade",
"Sec-WebSocket-Accept": "NO+pj7z0cvnNj//mlwRuAnCYqCE="
Sec-WebSocket-Acceptbase64(hsa1(sec-websocket-key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11))
Sec-WebSocket-AcceptSec-WebSocket-Accept dismatchWebsocketonopen
2、传输阶段
WebSocketframeframe
这样做会有几个好处:
HTTPchunk
WebSocket
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(1 bit):
表示信息的最后一帧,flag,也就是标记符。
PS:当然第一个消息片断也可能是最后的一个消息片断;RSV1、RSV2、RSV3(均为1 bit):
默认均为0。如果有约定自定义协议则不为0,一般均为0。(协议扩展用)Opcode(4 bit):
定义有效负载数据,如果收到了一个未知的操作码,连接也必须断掉,以下是定义的操作码:
Mask17 bit7+16 bit7+64 bit
7 bit000000011111010125
(7+16) bit1111110(即126)126
(7+64) bit1111111(即127)127
| 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位无符号数,这个数用来表示传输数据的长度。
0 bit14 bit1
maskMasking-key
应用数据的长度 = 负载数据的长度 - 扩展数据的长度Application data = Payload data - Extension data
四、iOS 中 WebSocket 相关框架
WebSocket(iOS客户端):
Socket(iOS客户端):
五、使用Starscream(swift)完成客户端长链需求
首先附上Starscream:GitHub地址
Starsream
Podfile
pod 'Starscream', '~> 4.0.0'
pod install
第二步:实现WebSocket能力。
import StarscreamWebSocket
private func initWebSocket() {
// 包装请求头
var request = URLRequest(url: URL(string: "ws://127.0.0.1:8000/chat")!)
request.timeoutInterval = 5 // Sets the timeout for the connection
request.setValue("some message", forHTTPHeaderField: "Qi-WebSocket-Header")
request.setValue("some message", forHTTPHeaderField: "Qi-WebSocket-Protocol")
request.setValue("0.0.1", forHTTPHeaderField: "Qi-WebSocket-Version")
request.setValue("some message", forHTTPHeaderField: "Qi-WebSocket-Protocol-2")
socketManager = WebSocket(request: request)
socketManager?.delegate = self
}
同时,我用三个Button的点击事件,分别模拟了connect(连接)、write(通信)、disconnect(断开)。
```swift
// Mark - Actions
// 连接
@objc func connetButtonClicked() {
socketManager?.connect()
}
// 通信
@objc func sendButtonClicked() {
socketManager?.write(string: "some message.")
}
// 断开