websocket协议,如何实现 ping / pong 心跳机制?
发布于 作者:苏南大叔 来源:程序如此灵动~
聚焦于websocket协议的心跳机制,按着最通俗的理解,服务器和客户端双方,一方发送ping,另外一方回复pong,就完成了心跳检测了。在websocket协议里面,都是ws.send(msg)发送消息的。所以,把msg换成ping或者pong字符串就可以了,对么?显然这是个陷阱式提问,答案必然不是这样。

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。测试环境:win10,nodejs@20.18.0,ws@8.18.0。
前文回顾
基于nodejs,可以实现websocket的双方通信。参考文章:
服务器端需要安装ws第三方库文件。参考命令:
npm i ws --save心跳机制
不同于通俗理解上的ping和pong消息发送。websocket协议里面的ping和pong,仅仅是报文里面的一个状态位置,并不是消息体。
服务器端的ws拥有ws.ping()和ws.on('pong')事件,而浏览器客户端的原生WebSocket里面,并没有.ping()或者.pong()函数。
逻辑是这样的:
服务器端,定期轮询去ping()客户端,而浏览器客户端,被动隐式的.pong()(代码里面是没写的)。而通过服务器端的ws.on('pong')事件,来获得pong事件。
服务器端:
let WebSocket = require("ws");
let server = new WebSocket.Server({ port: 8080 });
const clients = new Set();
let interval;
server.on("connection", function connection(ws) {
clients.add(ws);
ws.isAlive = true;
interval = setInterval(function ping() { // ping
clients.forEach((ws) => {
if (ws.isAlive === false) {
clients.delete(ws);
return ws.terminate();
}
ws.ping(() => {
console.log('ping sent');
});
});
}, 5000);
ws.on('pong', () => { // pong
ws.isAlive = true;
console.log('pong received');
});
ws.on("close", function close() {
ws.isAlive = false;
clients.delete(ws);
});
});
server.on("close", function close() {
clearInterval(interval);
});客户端浏览器什么都不做,因为没有办法主动ping,pong还是个被动技能。
广播
广播并不是内置的功能,它是建立在对客户端ws 对象的收集的基础上的。通过对在线的客户端进行遍历,然后每个都发送广播消息。
let WebSocket = require("ws");
let server = new WebSocket.Server({ port: 8080 });
const clients = new Set();
server.on("connection", function connection(ws) {
clients.add(ws);
ws.isAlive = true;
//...
function broadcast(data) {
clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
}
// setInterval(()=>{
// broadcast(Date.now());
// }, 5000);
});踢人
在一定的机制下,服务器端是可以主动断开链接的,也就是俗称的踢人。关键代码如下:
server.clients.forEach((ws)=>{
if (ws.isAlive === false) {
//...
return ws.terminate();
}
});完整代码

服务端:
newsn.net:这里是【评论】可见内容
客户端:
let ws = new WebSocket("ws://localhost:8080");
ws.onopen = function () {
ws.send("苏南");
};
ws.onclose = () => {
console.log("服务器断开链接");
};
ws.onerror = () => {
console.log("有错误发生");
};
ws.onmessage = function (e) {
let msg = e.data;
console.log("客户端收到消息:%s", msg);
};相关文档
- 在线的客户端测试,可以发送和接收消息 http://www.websocket-test.com/