LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

【WEB开发】websocket心跳保持连接机制

admin
2025年3月31日 18:17 本文热度 212

心跳机制在 WebSocket 通信中是一种常用的技术,用于维持连接的稳定性、检测连接是否正常。以下为你详细介绍在前端使用 WebSocket 时如何实现心跳机制,以及相关代码示例。

实现思路

  • 发送心跳包:客户端定期向服务器发送一个特定格式的消息(心跳包),以表明自己处于活跃状态。
  • 接收响应:服务器收到心跳包后,返回一个响应消息,客户端通过检查是否收到响应来判断连接是否正常。
  • 超时处理:如果客户端在一定时间内没有收到服务器的响应,认为连接可能出现问题,尝试重新连接。

示例代码

class WebSocketClient {
    constructor(url) {
        this.url = url;
        this.socket = null;
        this.reconnectInterval = 5000; // 重连间隔时间,单位:毫秒
        this.reconnectTimer = null;
        this.messageHandlers = [];
        this.errorHandlers = [];
        this.openHandlers = [];
        this.closeHandlers = [];

        this.heartbeatInterval = 3000; // 心跳间隔时间,单位:毫秒
        this.heartbeatTimer = null;
        this.lastHeartbeatResponseTime = null;
        this.heartbeatTimeout = 5000; // 心跳超时时间,单位:毫秒
        this.heartbeatTimeoutTimer = null;

        this.tryConnect();
    }

    // 尝试建立连接
    tryConnect() {
        this.socket = new WebSocket(this.url);

        this.socket.onopen = () => {
            console.log('WebSocket 连接已建立');
            clearInterval(this.reconnectTimer);
            this.openHandlers.forEach(handler => handler());
            this.startHeartbeat();
        };

        this.socket.onmessage = (event) => {
            if (event.data === 'heartbeat_response') {
                this.lastHeartbeatResponseTime = Date.now();
                clearTimeout(this.heartbeatTimeoutTimer);
                this.heartbeatTimeoutTimer = setTimeout(() => {
                    this.handleHeartbeatTimeout();
                }, this.heartbeatTimeout);
            } else {
                this.messageHandlers.forEach(handler => handler(event.data));
            }
        };

        this.socket.onerror = (error) => {
            console.error('WebSocket 连接出错:', error);
            this.errorHandlers.forEach(handler => handler(error));
            this.reconnect();
        };

        this.socket.onclose = (event) => {
            console.log('WebSocket 连接已关闭,代码:', event.code, '原因:', event.reason);
            this.closeHandlers.forEach(handler => handler(event));
            this.reconnect();
            this.stopHeartbeat();
        };
    }

    // 重连机制
    reconnect() {
        if (!this.reconnectTimer) {
            this.reconnectTimer = setInterval(() => {
                console.log('尝试重新连接 WebSocket...');
                this.tryConnect();
            }, this.reconnectInterval);
        }
    }

    // 发送消息
    sendMessage(message) {
        if (this.socket && this.socket.readyState === WebSocket.OPEN) {
            this.socket.send(message);
        } else {
            console.error('无法发送消息,WebSocket 未连接');
        }
    }

    // 添加消息处理函数
    onMessage(handler) {
        this.messageHandlers.push(handler);
    }

    // 添加错误处理函数
    onError(handler) {
        this.errorHandlers.push(handler);
    }

    // 添加连接打开处理函数
    onOpen(handler) {
        this.openHandlers.push(handler);
    }

    // 添加连接关闭处理函数
    onClose(handler) {
        this.closeHandlers.push(handler);
    }

    // 关闭连接
    close() {
        if (this.socket) {
            clearInterval(this.reconnectTimer);
            this.socket.close();
            this.stopHeartbeat();
        }
    }

    // 启动心跳机制
    startHeartbeat() {
        this.heartbeatTimer = setInterval(() => {
            this.sendMessage('heartbeat');
            this.heartbeatTimeoutTimer = setTimeout(() => {
                this.handleHeartbeatTimeout();
            }, this.heartbeatTimeout);
        }, this.heartbeatInterval);
    }

    // 停止心跳机制
    stopHeartbeat() {
        clearInterval(this.heartbeatTimer);
        clearTimeout(this.heartbeatTimeoutTimer);
    }

    // 处理心跳超时
    handleHeartbeatTimeout() {
        console.log('心跳超时,尝试重新连接...');
        this.socket.close();
    }
}

// 使用示例
const socketClient = new WebSocketClient('ws://echo.websocket.org');

// 监听消息
socketClient.onMessage((message) => {
    console.log('收到消息:', message);
});

// 监听连接打开
socketClient.onOpen(() => {
    console.log('连接已打开');
});

// 监听错误
socketClient.onError((error) => {
    console.error('发生错误:', error);
});

// 监听连接关闭
socketClient.onClose((event) => {
    console.log('连接关闭:', event);
});

代码解释

  1. 构造函数:除了初始化基本的 WebSocket 连接参数外,还初始化了心跳机制相关的参数,如心跳间隔时间 heartbeatInterval、心跳超时时间 heartbeatTimeout 等。
  2. startHeartbeat 方法:使用 setInterval 定时发送心跳包(heartbeat),并启动一个定时器 heartbeatTimeoutTimer 用于检测心跳超时。
  3. onmessage 事件处理:当收到服务器的心跳响应消息(heartbeat_response)时,更新最后一次收到响应的时间 lastHeartbeatResponseTime,并重置心跳超时定时器。
  4. handleHeartbeatTimeout 方法:当心跳超时发生时,关闭当前的 WebSocket 连接,触发重连机制。
  5. stopHeartbeat 方法:停止心跳定时器和超时定时器。

通过上述代码,你可以在前端 WebSocket 通信中实现一个简单的心跳机制,确保连接的稳定性。同时,服务器端也需要相应地处理心跳包并返回响应消息。

分享

用ping\pong来实现

在 WebSocket 通信里,ping 和 pong 是标准的心跳机制实现方式。ping 是客户端或服务器发送的探测消息,pong 则是对 ping 的响应。下面是一个使用 JavaScript 封装 WebSocket 并利用 ping/pong 实现心跳机制的详细示例。

实现思路

  • 客户端:周期性地发送 ping 消息,同时监听 pong 响应,若超时未收到 pong 则认为连接异常。
  • 服务器端:接收到 ping 消息后,立即返回 pong 响应。

前端代码示例

class WebSocketWithPingPong {
    constructor(url) {
        this.url = url;
        this.socket = null;
        this.pingInterval = 5000; // 发送 ping 消息的间隔时间(毫秒)
        this.pongTimeout = 3000; // 等待 pong 响应的超时时间(毫秒)
        this.pingTimer = null;
        this.pongTimeoutTimer = null;
        this.reconnectInterval = 5000; // 重连间隔时间(毫秒)
        this.reconnectTimer = null;
        this.messageHandlers = [];
        this.errorHandlers = [];
        this.openHandlers = [];
        this.closeHandlers = [];

        this.connect();
    }

    connect() {
        this.socket = new WebSocket(this.url);

        this.socket.onopen = () => {
            console.log('WebSocket 连接已建立');
            clearInterval(this.reconnectTimer);
            this.openHandlers.forEach(handler => handler());
            this.startPing();
        };

        this.socket.onmessage = (event) => {
            if (event.data === 'pong') {
                clearTimeout(this.pongTimeoutTimer);
            } else {
                this.messageHandlers.forEach(handler => handler(event.data));
            }
        };

        this.socket.onerror = (error) => {
            console.error('WebSocket 连接出错:', error);
            this.errorHandlers.forEach(handler => handler(error));
            this.reconnect();
        };

        this.socket.onclose = (event) => {
            console.log('WebSocket 连接已关闭,代码:', event.code, '原因:', event.reason);
            this.closeHandlers.forEach(handler => handler(event));
            this.reconnect();
            this.stopPing();
        };
    }

    reconnect() {
        if (!this.reconnectTimer) {
            this.reconnectTimer = setInterval(() => {
                console.log('尝试重新连接 WebSocket...');
                this.connect();
            }, this.reconnectInterval);
        }
    }

    sendMessage(message) {
        if (this.socket && this.socket.readyState === WebSocket.OPEN) {
            this.socket.send(message);
        } else {
            console.error('无法发送消息,WebSocket 未连接');
        }
    }

    onMessage(handler) {
        this.messageHandlers.push(handler);
    }

    onError(handler) {
        this.errorHandlers.push(handler);
    }

    onOpen(handler) {
        this.openHandlers.push(handler);
    }

    onClose(handler) {
        this.closeHandlers.push(handler);
    }

    close() {
        if (this.socket) {
            clearInterval(this.reconnectTimer);
            this.socket.close();
            this.stopPing();
        }
    }

    startPing() {
        this.pingTimer = setInterval(() => {
            this.sendMessage('ping');
            this.pongTimeoutTimer = setTimeout(() => {
                this.handlePongTimeout();
            }, this.pongTimeout);
        }, this.pingInterval);
    }

    stopPing() {
        clearInterval(this.pingTimer);
        clearTimeout(this.pongTimeoutTimer);
    }

    handlePongTimeout() {
        console.log('未收到 pong 响应,尝试重新连接...');
        this.socket.close();
    }
}

// 使用示例
const socket = new WebSocketWithPingPong('ws://your-websocket-server-url');

socket.onOpen(() => {
    console.log('连接已打开');
});

socket.onMessage((message) => {
    console.log('收到消息:', message);
});

socket.onError((error) => {
    console.error('发生错误:', error);
});

socket.onClose((event) => {
    console.log('连接关闭:', event);
});

代码解释

  1. 构造函数:初始化 WebSocket 连接所需的参数,包括 ping 发送间隔、pong 超时时间、重连间隔等,并且调用 connect 方法开始建立连接。
  2. connect 方法:创建 WebSocket 实例,为 onopenonmessageonerror 和 onclose 事件绑定处理函数。连接建立成功后,启动 ping 发送机制。
  3. startPing 方法:使用 setInterval 周期性地发送 ping 消息,同时启动一个 pong 超时定时器。
  4. onmessage 事件处理:当收到 pong 响应时,清除 pong 超时定时器;若收到其他消息,则调用注册的消息处理函数。
  5. handlePongTimeout 方法:若在 pong 超时时间内未收到 pong 响应,关闭当前连接并触发重连机制。
  6. 其他方法:如 sendMessage 用于发送消息,onMessageonErroronOpen 和 onClose 用于注册相应的事件处理函数,close 用于关闭连接,stopPing 用于停止 ping 发送和 pong 超时检测。

服务器端示例(使用 Node.js 和 ws 库)

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', (ws) => {
    ws.on('message', (message) => {
        if (message === 'ping') {
            ws.send('pong');
        } else {
            // 处理其他消息
            console.log('收到消息:', message);
        }
    });
});

console.log('WebSocket 服务器已启动,监听端口 8080');

服务器端代码解释

  • 使用 ws 库创建一个 WebSocket 服务器,监听 8080 端口。
  • 当有客户端连接时,监听 message 事件,若收到 ping 消息,立即返回 pong 响应;若收到其他消息,则进行相应处理。

作者:coding_time
链接:https://juejin.cn/post/7475896691884900390
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

该文章在 2025/4/1 12:59:13 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved