简介
ws 是 websocket 的简称
WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。
特点
它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
Http或https 都是一种单项交流,由客户端主动发起,通过一系列的校验流程,最终完成消息的传送
还有一些比较好的优点:
-
建立在 TCP 协议之上,服务器端的实现比较容易。
-
与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
-
没有同源限制,客户端可以与任意服务器通信。
Ws 有两种类型,类似 http 和 https ,特点是加密的区分
地址分别对应
ws://example.com:80/some/path
wss://example.com:443/some/path
例子
我们来先看一个简单的例子
const ws = new WebSocket('wss://echo.websocket.org');
ws.onopen = function(evt) {
console.log('Connection open ...');
ws.send('Hello WebSockets!');
};
ws.onmessage = function(evt) {
console.log(`Received Message: ${evt.data}`);
ws.close();
};
ws.onerror = function(evt) {
console.log('evt: Connection error');
};
ws.onclose = function(evt) {
console.log('Connection closed.');
};
ws.send(msg);
Ws 需要通过 new Websocket() 产生一个实例,并且在这个过程中需要把要连接的地址写入实例中,执行语句之后,客户端就会与服务器进行连接。实例对象的所有属性和方法清单,可以参照这里。
api简单介绍
Ws 中监听实例的当前状态 需要用readyState, 共有四种
-
CONNECTING:值为0,表示正在连接。
-
OPEN:值为1,表示连接成功,可以通信了。
-
CLOSING:值为2,表示连接正在关闭。
-
CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
// 可以是这样
switch (ws.readyState) {
case WebSocket.CONNECTING: // do something
break;
case WebSocket.OPEN: // do something
break;
case WebSocket.CLOSING: // do something
break;
case WebSocket.CLOSED: // do something
break;
default:
// this never happens
break;
}
// 也可以这样
if(ws.readyState === 1) {};
if(ws.readyState === 2) {};
if(ws.readyState === 3) {};
Ws 存在5个基础的api 回调
onopen onmessage onerror onclose send
Onopen 初始连接成功后 触发,只会触发一次
Onmessage 则是在连接成功后 结束之前 所有的信息推送的回调,具体涉及数据逻辑 这个阶段进行处理
Onclose 断开连接时 触发,同样只会触发一次 注意 onmessage 阶段 接收到的消息有可能是 string 也可能是二进制(blob对象或Arraybuffer对象)。
ws.onmessage = function(event){
if(typeof event.data === String) {
console.log("Received data string");
}
if(event.data instanceof ArrayBuffer){
var buffer = event.data;
console.log("Received arraybuffer");
}
}
这个接受的信息类型,可以与第三方或者服务端沟通清楚,最终我们在处理数据的时候统一一种,便于数据的处理
ws.send() 用于向服务端发送数据 可以是文本 也可以是二进制数据
ws.send('your message');
// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i];
}
ws.send(binary.buffer);
当我们发送二进制的数据的时候,是可以监听到 消息剩余多少没有发送,用到ws.bufferedAmount,bufferedAmount 为 0 时 代表着消息发送完毕
var data = new ArrayBuffer(10000000);
ws.send(data);
// console.log(ws.bufferedAmount)
if (ws.bufferedAmount === 0) {
// 发送完毕
} else {
// 发送还没结束
}
下面举一个处理数据的例子
const handleMessage = async (elinkCno: string, ws: WebSocket, evt: MessageEvent) => {
const { data } = evt;
// console.log('===========data========', data);
Reflect.ownKeys(eLinkStateObj).forEach(v => {
eLinkStateObj[v].forEach((m: string) => {
if (data.includes(m)) eLinkObj.state = v;
});
});
// console.log('数组处理后的state', eLinkObj.state);
if (eLinkObj.state === 'NOTINFORCE') {
doSend(ws, `AgentCallbackLogin|agent-login|${elinkCno}|${elinkCno}`);
}
if (data === 'doLoginOK') doSend(ws, `AgentStatus|${elinkCno}`);
if (data === 'HeartBeat') doSend(ws, 'HeartBeat');
if (eLinkObj.state === 'OFFLINE' && data.includes('QTdoLoginOff')) return;
};
const doSend = (
websocket: WebSocket,
msg: string | ArrayBuffer | SharedArrayBuffer | Blob | ArrayBufferView,
) => {
if (!websocket) return;
// 当readyState不为1时不发送消息
if (websocket.readyState !== 1) {
// console.log('WebSocket is already in CLOSING or CLOSED state');
} else {
websocket.send(msg);
}
};
Onerror 处理报错时的回调函数。这个函数使用的频率很少,除非有指定的错误,来单独处理,一般会在函数里面通过sentry来捕获发生的错误
ws.onerror = (event) => {
// handle error event
};
整体流程
一般我们在和服务端连接过程中 有这么几个步骤
- 建立连接
- 连接成功,登录
- 登录成功,确认登录后的账户,设定登录状态
- 心跳开始, 并且在整个连接过程中一直互通
- 消息接收,数据处理
- 连接关闭
连接关闭可能是手动,也可能是被动,一般被动的情况下,会有服务端持续发送的消息提醒,如果消息在一定的次数内没有回应,服务端则会自动关闭当前管道的连接。