WebSocket详解
一.什么是 WebSocket?
WebSocket 是一种在单个 TCP 连接上进行全双工(双向)通信的协议。它是为了弥补传统 HTTP 协议在实时通信场景中的不足而设计的,允许浏览器和服务器之间进行低延迟的实时数据传输
二.WebSocket的优势
WebSocket 与 HTTP 的区别
我们再来看看与其他实时通讯技术的对比
- 带宽浪费:频繁发送无效请求。
- 服务器负担大:每个请求都需要重新建立连接并处理。
- 更低的延迟:由于连接持续存在。
- 资源消耗大:等待响应之后再关闭,还是有重复连接
- 实现简单:只需服务器推送数据。
- 不适合双向实时应用:无法进行双向数据交互。
- 浏览器兼容性差:部分浏览器不完全支持 SSE。
三.WebSocket的属性和方法
WebSocket 属性
url
new WebSocket(\'wss://example.com\');
readyState
0
(连接中)、1
(已连接)、2
(关闭中)、3
(已关闭)。console.log(socket.readyState);
bufferedAmount
console.log(socket.bufferedAmount);
protocol
console.log(socket.protocol);
extensions
console.log(socket.extensions);
WebSocket 方法
send()
socket.send(\"Hello, Server!\");
close()
socket.close();
WebSocket 事件
onopen
onmessage
onclose
onerror
WebSocket 连接状态常量(readyState
)
0
(CONNECTING)1
(OPEN)2
(CLOSING)3
(CLOSED)
实例:
function webSocketManager(options) { if (!options.url) { throw new Error(\"url必传\"); } if (!options.bizMessageHandler) { throw new Error(\"bizMessageHandler必传\"); } this.url = options.url; this.heartbeatInterval = options.heartbeatInterval || 10; // 心跳间隔,单位:秒 this.heartbeatStopCount = options.heartbeatStopCount || 3; // 心跳几次没响应就停止,默认3次 this.autoReconnect = options.autoReconnect || true; // 断开后是否自动重连 this.reconnectMinDuration = options.reconnectMinDuration || 10; // 重连最小间隔时间,单位:秒 this.bizMessageHandler = options.bizMessageHandler; // 业务消息处理函数 this.onConnectionOpen = options.onConnectionOpen; // 建立连接时回调}webSocketManager.prototype.init = function() { this._connect();};webSocketManager.prototype._startHeartbeat = function() { let _this = this; this._log(\"start heartbeat\"); this.lastSendSeq = 0; // 最后一次发出的序列号 this.lastReceiveSeq = 0; // 最后一次收到的序列号 this.webSocket.addEventListener(\"message\", function(e) { let data = parseInt(e.data); if (!isNaN(data)) { _this.lastReceiveSeq = data; } }); this.heartbeatTimerId = window.setInterval(function() { let noRespCount = _this.lastSendSeq - _this.lastReceiveSeq; if (noRespCount >= _this.heartbeatStopCount) { _this._log(`心跳包未响应超过${_this.heartbeatStopCount}次, 主动断开连接`); _this.webSocket.close(); _this._stopHeartbeat(); return; } _this.webSocket.send(_this.lastSendSeq++); }, this.heartbeatInterval * 1000);};webSocketManager.prototype._stopHeartbeat = function() { if (null != this.heartbeatTimerId) { this._log(\"stop heartbeat\"); window.clearInterval(this.heartbeatTimerId); this.heartbeatTimerId = null; }};// 连接建立webSocketManager.prototype._connect = function() { let _this = this; this.webSocket = new WebSocket(this.url); this.connectTime = new Date().getTime(); // 连接建立成功 this.webSocket.onopen = function() { _this._log(\"onopen\"); if (_this.onConnectionOpen) { _this.onConnectionOpen(); } _this._startHeartbeat(); }; // 连接建立失败 this.webSocket.onerror = function() { _this._log(\"onerror\"); }; // 连接断开 this.webSocket.onclose = function() { _this._log(\"onclose\"); _this._stopHeartbeat(); // 如果设置为自动重连就自动重连 if (_this.autoReconnect) { // 为了避免断网时频繁不停重连的情况,需要判断下上次连接时间 let duration = new Date().getTime() - _this.connectTime; // 如果重连小于最小间隔的时间,则延迟再重连,否则马上重连 if (duration < _this.reconnectMinDuration * 1000) { setTimeout(function() { _this._connect(); }, _this.reconnectMinDuration * 1000 - duration); } else { _this._connect(); } } }; this.webSocket.addEventListener(\"message\", function(e) { let msg = e.data; // _this._log(`onmessage; message is ${msg}`); // 如果是业务消息则回调业务消息处理函数 if (_this._isBizMessage(msg)) { _this.bizMessageHandler(msg); } });};webSocketManager.prototype._isBizMessage = function(msg) { return msg && msg.indexOf(\"{\") === 0;};webSocketManager.prototype._log = function(msg) { if (console && console.log) { console.log(`[webSocketManager] ${new Date().getTime()} ${msg}`); }};export default webSocketManager;