男女做爽爽爽网站-男女做羞羞高清-男女做爰高清无遮挡免费视频-男女做爰猛烈-男女做爰猛烈吃奶啪啪喷水网站-内射白浆一区

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

【W(wǎng)EB開發(fā)】websocket心跳保持連接機(jī)制

admin
2025年3月31日 18:17 本文熱度 595

心跳機(jī)制在 WebSocket 通信中是一種常用的技術(shù),用于維持連接的穩(wěn)定性、檢測連接是否正常。以下為你詳細(xì)介紹在前端使用 WebSocket 時(shí)如何實(shí)現(xiàn)心跳機(jī)制,以及相關(guān)代碼示例。

實(shí)現(xiàn)思路

  • 發(fā)送心跳包:客戶端定期向服務(wù)器發(fā)送一個特定格式的消息(心跳包),以表明自己處于活躍狀態(tài)。
  • 接收響應(yīng):服務(wù)器收到心跳包后,返回一個響應(yīng)消息,客戶端通過檢查是否收到響應(yīng)來判斷連接是否正常。
  • 超時(shí)處理:如果客戶端在一定時(shí)間內(nèi)沒有收到服務(wù)器的響應(yīng),認(rèn)為連接可能出現(xiàn)問題,嘗試重新連接。

示例代碼

class WebSocketClient {
    constructor(url) {
        this.url = url;
        this.socket = null;
        this.reconnectInterval = 5000; // 重連間隔時(shí)間,單位:毫秒
        this.reconnectTimer = null;
        this.messageHandlers = [];
        this.errorHandlers = [];
        this.openHandlers = [];
        this.closeHandlers = [];

        this.heartbeatInterval = 3000; // 心跳間隔時(shí)間,單位:毫秒
        this.heartbeatTimer = null;
        this.lastHeartbeatResponseTime = null;
        this.heartbeatTimeout = 5000; // 心跳超時(shí)時(shí)間,單位:毫秒
        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 連接已關(guān)閉,代碼:', event.code, '原因:', event.reason);
            this.closeHandlers.forEach(handler => handler(event));
            this.reconnect();
            this.stopHeartbeat();
        };
    }

    // 重連機(jī)制
    reconnect() {
        if (!this.reconnectTimer) {
            this.reconnectTimer = setInterval(() => {
                console.log('嘗試重新連接 WebSocket...');
                this.tryConnect();
            }, this.reconnectInterval);
        }
    }

    // 發(fā)送消息
    sendMessage(message) {
        if (this.socket && this.socket.readyState === WebSocket.OPEN) {
            this.socket.send(message);
        } else {
            console.error('無法發(fā)送消息,WebSocket 未連接');
        }
    }

    // 添加消息處理函數(shù)
    onMessage(handler) {
        this.messageHandlers.push(handler);
    }

    // 添加錯誤處理函數(shù)
    onError(handler) {
        this.errorHandlers.push(handler);
    }

    // 添加連接打開處理函數(shù)
    onOpen(handler) {
        this.openHandlers.push(handler);
    }

    // 添加連接關(guān)閉處理函數(shù)
    onClose(handler) {
        this.closeHandlers.push(handler);
    }

    // 關(guān)閉連接
    close() {
        if (this.socket) {
            clearInterval(this.reconnectTimer);
            this.socket.close();
            this.stopHeartbeat();
        }
    }

    // 啟動心跳機(jī)制
    startHeartbeat() {
        this.heartbeatTimer = setInterval(() => {
            this.sendMessage('heartbeat');
            this.heartbeatTimeoutTimer = setTimeout(() => {
                this.handleHeartbeatTimeout();
            }, this.heartbeatTimeout);
        }, this.heartbeatInterval);
    }

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

    // 處理心跳超時(shí)
    handleHeartbeatTimeout() {
        console.log('心跳超時(shí),嘗試重新連接...');
        this.socket.close();
    }
}

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

// 監(jiān)聽消息
socketClient.onMessage((message) => {
    console.log('收到消息:', message);
});

// 監(jiān)聽連接打開
socketClient.onOpen(() => {
    console.log('連接已打開');
});

// 監(jiān)聽錯誤
socketClient.onError((error) => {
    console.error('發(fā)生錯誤:', error);
});

// 監(jiān)聽連接關(guān)閉
socketClient.onClose((event) => {
    console.log('連接關(guān)閉:', event);
});

代碼解釋

  1. 構(gòu)造函數(shù):除了初始化基本的 WebSocket 連接參數(shù)外,還初始化了心跳機(jī)制相關(guān)的參數(shù),如心跳間隔時(shí)間 heartbeatInterval、心跳超時(shí)時(shí)間 heartbeatTimeout 等。
  2. startHeartbeat 方法:使用 setInterval 定時(shí)發(fā)送心跳包(heartbeat),并啟動一個定時(shí)器 heartbeatTimeoutTimer 用于檢測心跳超時(shí)。
  3. onmessage 事件處理:當(dāng)收到服務(wù)器的心跳響應(yīng)消息(heartbeat_response)時(shí),更新最后一次收到響應(yīng)的時(shí)間 lastHeartbeatResponseTime,并重置心跳超時(shí)定時(shí)器。
  4. handleHeartbeatTimeout 方法:當(dāng)心跳超時(shí)發(fā)生時(shí),關(guān)閉當(dāng)前的 WebSocket 連接,觸發(fā)重連機(jī)制。
  5. stopHeartbeat 方法:停止心跳定時(shí)器和超時(shí)定時(shí)器。

通過上述代碼,你可以在前端 WebSocket 通信中實(shí)現(xiàn)一個簡單的心跳機(jī)制,確保連接的穩(wěn)定性。同時(shí),服務(wù)器端也需要相應(yīng)地處理心跳包并返回響應(yīng)消息。

分享

用ping\pong來實(shí)現(xiàn)

在 WebSocket 通信里,ping 和 pong 是標(biāo)準(zhǔn)的心跳機(jī)制實(shí)現(xiàn)方式。ping 是客戶端或服務(wù)器發(fā)送的探測消息,pong 則是對 ping 的響應(yīng)。下面是一個使用 JavaScript 封裝 WebSocket 并利用 ping/pong 實(shí)現(xiàn)心跳機(jī)制的詳細(xì)示例。

實(shí)現(xiàn)思路

  • 客戶端:周期性地發(fā)送 ping 消息,同時(shí)監(jiān)聽 pong 響應(yīng),若超時(shí)未收到 pong 則認(rèn)為連接異常。
  • 服務(wù)器端:接收到 ping 消息后,立即返回 pong 響應(yīng)。

前端代碼示例

class WebSocketWithPingPong {
    constructor(url) {
        this.url = url;
        this.socket = null;
        this.pingInterval = 5000; // 發(fā)送 ping 消息的間隔時(shí)間(毫秒)
        this.pongTimeout = 3000; // 等待 pong 響應(yīng)的超時(shí)時(shí)間(毫秒)
        this.pingTimer = null;
        this.pongTimeoutTimer = null;
        this.reconnectInterval = 5000; // 重連間隔時(shí)間(毫秒)
        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 連接已關(guān)閉,代碼:', 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('無法發(fā)送消息,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 響應(yīng),嘗試重新連接...');
        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('發(fā)生錯誤:', error);
});

socket.onClose((event) => {
    console.log('連接關(guān)閉:', event);
});

代碼解釋

  1. 構(gòu)造函數(shù):初始化 WebSocket 連接所需的參數(shù),包括 ping 發(fā)送間隔、pong 超時(shí)時(shí)間、重連間隔等,并且調(diào)用 connect 方法開始建立連接。
  2. connect 方法:創(chuàng)建 WebSocket 實(shí)例,為 onopenonmessageonerror 和 onclose 事件綁定處理函數(shù)。連接建立成功后,啟動 ping 發(fā)送機(jī)制。
  3. startPing 方法:使用 setInterval 周期性地發(fā)送 ping 消息,同時(shí)啟動一個 pong 超時(shí)定時(shí)器。
  4. onmessage 事件處理:當(dāng)收到 pong 響應(yīng)時(shí),清除 pong 超時(shí)定時(shí)器;若收到其他消息,則調(diào)用注冊的消息處理函數(shù)。
  5. handlePongTimeout 方法:若在 pong 超時(shí)時(shí)間內(nèi)未收到 pong 響應(yīng),關(guān)閉當(dāng)前連接并觸發(fā)重連機(jī)制。
  6. 其他方法:如 sendMessage 用于發(fā)送消息,onMessageonErroronOpen 和 onClose 用于注冊相應(yīng)的事件處理函數(shù),close 用于關(guān)閉連接,stopPing 用于停止 ping 發(fā)送和 pong 超時(shí)檢測。

服務(wù)器端示例(使用 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 服務(wù)器已啟動,監(jiān)聽端口 8080');

服務(wù)器端代碼解釋

  • 使用 ws 庫創(chuàng)建一個 WebSocket 服務(wù)器,監(jiān)聽 8080 端口。
  • 當(dāng)有客戶端連接時(shí),監(jiān)聽 message 事件,若收到 ping 消息,立即返回 pong 響應(yīng);若收到其他消息,則進(jìn)行相應(yīng)處理。

作者:coding_time
鏈接:https://juejin.cn/post/7475896691884900390
來源:稀土掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

該文章在 2025/4/1 12:59:13 編輯過
點(diǎn)晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 亚洲午夜无码毛片AV久久久久久 | 强制潮喷失禁调教sm在线 | 亚洲午夜A片一区二区 | 亚州欧美中文字幕精品综合 | 黑巨人与欧美精品一区 | 亚洲伊人情人综合网站 | 成人片在线观看免费人A片 成人片在线观看视频 | 久久99精品久久久久久秒播 | 亚洲三级黄色片 | 久久久亚洲熟妇熟女ⅹxxx影视 | 日韩一区二区三区免费播放 | 免费看美女自慰的网站 | 精品久久无码AV片软件 | 国产三级a在线 | 任你躁国产自任一区二区三区 | 亚洲av无码片在线播放 | 亚洲精品色情影片 | 免费欧美久久精品国产一区二区 | 丁香五月激情综合亚洲 | 麻豆视频观看网站 | 欧美日韩免费高清视频一区二区 | 久久精品蜜桃中文字幕无码 | 亚洲国产欧美国产第一区二区 | 老司国产高清免费视频 | 人妻丰满a | 精品一区二区三区标清tc免费在线播放 | 中文一区二区三区亚洲欧美 | 国产三级精品三级在线专 | 四虎影视8848a四虎在线播放 | 亚洲丁香五月天缴情综合 | 天堂岛WWW最新版在线资源 | 99这里是99在线视频 | 99热精品一区 | 波多野吉衣一区 | 情人伊人久久综合亚洲 | 羞国产在线拍揄自揄视频 | 91亚洲精品福利在线播放 | 中文字幕一区二区三区在线观看 | 纯肉高H种马艳遇风流多 | 在线视频 国产精品 中文字幕 | 精品国产福利在线视频 |