WebSocket
WebSocket 用于在客户端和服务端之间建立持久连接、进行全双工通信。
聊天软件、网络游戏、实时交易系统等应用需要使用 WebSocket。
WebSocket 基本使用
创建 socket
socket (套接字) 是数据传输的一个端点,首先需要创建 socket,用于后续的数据交互。
js
let socket = new WebSocket("ws://javascript.info");
WebSocket 使用 ws
协议,类似于 HTTP,还有类似于 HTTPS 的 wss
。
监听事件
socket 会触发 4 种事件:
open
:连接建立message
:接收到消息error
:发生错误close
:连接关闭
使用 on<event>
添加事件处理函数,使用 socket.send
发送数据。
js
socket.onopen = function(e) {
alert("[open] Connection established");
alert("Sending to server");
socket.send("My name is John");
};
socket.onmessage = function(event) {
alert(`[message] Data received from server: ${event.data}`);
};
socket.onclose = function(event) {
if (event.wasClean) {
alert(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
} else {
// 例如服务器进程被杀死或网络中断
// 在这种情况下,event.code 通常为 1006
alert('[close] Connection died');
}
};
socket.onerror = function(error) {
alert(`[error] ${error.message}`);
};
连接建立
WebSocket 建立连接时,首先使用 HTTP 询问服务端是否支持 WebSocket,如果支持则后续使用 WebSocket 进行通信。
假如要连接到 wss://javascript.info/chat
,HTTP 请求报文如下:
GET /chat
Host: javascript.info
Origin: https://javascript.info
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
Sec-WebSocket-Version: 13
GET
请求Origin
:当前页面 URL,WebSocket 原生支持跨域,不需要服务端做 CORSConnection: Upgrade
:客户端想要更改协议Upgrade: websocket
:更改为 WebSocket 协议Sec-WebSocket-Key
:浏览器随机生成的密钥Sec-WebSocket-Version
:WebSocket 协议版本
服务端同意切换为 WebSocket 时的响应报文:
101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=
Sec-WebSocket-Accept
:服务端使用特殊算法将Sec-WebSocket-Key
重新编码
数据传输
WebSocket 通信以 frame 为单位,有以下几种类型:
- text:文本数据
- binary data:二进制数据
- ping/pong:服务端检查连接
- connection close:连接关闭
send
只能发送文本或二进制数据,支持 String
、Blob
、ArrayBuffer
等类型。
socket.binaryType
指定二进制数据的格式,默认是 blob
。
流量控制
如果接收方的网速很慢,需要发送的数据就会大量缓存在发送方的内存中,可以通过检查已缓冲的字节数来调整发送速率,使缓存消耗的内存不至于过多:
js
// 每 100ms 检查一次 socket
// 仅当所有现有的数据都已被发送出去时,再发送更多数据
setInterval(() => {
if (socket.bufferedAmount == 0) {
socket.send(moreData());
}
}, 100);
连接关闭
通信双方都可以主动关闭连接,发送可选的 code 和 reason。
js
socket.close([code], [reason]);
常见 code:
1000
:默认,正常关闭1001
:一方离开,比如浏览器关闭页面1006
:连接丢失时自动发送,无法手动发送1009
:消息太大,无法处理1011
:服务端意外错误- 不能设置小于
1000
的 code
获取连接状态
socket.readyState
表示连接状态:
0
:CONNECTING,正在建立连接1
:OPEN,连接建立,通信中2
:CLOSING,正在关闭连接3
:CLOSED,连接已关闭