我们相信:世界是美好的,你是我也是。 来玩一下解压小游戏吧!

聚焦于websocket协议的心跳机制,按着最通俗的理解,服务器和客户端双方,一方发送ping,另外一方回复pong,就完成了心跳检测了。在websocket协议里面,都是ws.send(msg)发送消息的。所以,只是把msg换成ping或者pong字符串么?显然这是个陷阱式提问,答案必然不是这样。

苏南大叔:websocket协议,如何实现 ping / pong 心跳机制? - websocket-heartbeat
websocket协议,如何实现 ping / pong 心跳机制?(图2-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。测试环境:win10nodejs@20.18.0ws@8.18.0

前文回顾

基于nodejs,可以实现websocket的双方通信。参考文章:

服务器端需要安装ws第三方客户端。参考命令:

npm i ws --save
Plain text

心跳机制

不同于通俗理解上的pingpong消息发送。websocket协议里面的pingpong,仅仅是报文里面的一个状态位置,并不是消息体。

服务器端的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);
});
JavaScript

客户端浏览器什么都不做,因为没有办法主动pingpong还是个被动技能。

广播

广播并不是内置的功能,它是建立在对客户端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);
});
JavaScript

踢人

在一定的机制下,服务器端是可以主动断开链接的,也就是俗称的踢人。关键代码如下:

server.clients.forEach((ws)=>{
  if (ws.isAlive === false) {
    //...
    return ws.terminate();
  }
});
JavaScript

完整代码

苏南大叔:websocket协议,如何实现 ping / pong 心跳机制? - 代码
websocket协议,如何实现 ping / pong 心跳机制?(图2-2)

服务端:

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);
    });
    // ################################################
    // 消息发送/广播
    ws.on("message", (msg) => {
        console.log("received: %s", msg);
    });
    function broadcast(data) {
        clients.forEach((client) => {
            if (client.readyState === WebSocket.OPEN) {
                client.send(data);
            }
        });
    }
    // setInterval(()=>{
    //     broadcast(Date.now());
    // }, 15000);
    // ################################################
});
server.on("close", function close() {
    clearInterval(interval);
});
JavaScript

客户端:

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);
};
JavaScript

相关文档

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   socket