swoole 的練習 demo(5)- 加入心跳功能

yyy123456發表於2022-08-31

一直不能下決心好好學習,仔細研究一下,決定用盡量降低難度曲線的方法,從易到難,一步一步的學習,所以整了個demo專案。

git倉庫和使用步驟

確保能看到swoole,在 php -m 命令中
php -m 
git clone https://github.com/lang123789/swoole_demo.git
然後設定了標籤,本文對應 v5.0
cd swoole_demo
git checkout v5.0

有提示錯誤之類,但程式碼已經切換到 v5.0 了。

## 安裝類庫,生成 autoload.php 檔案
composer install
## 啟動 websocket 服務
php src/WebSocket/run.php

需求

9、加入心跳功能,確保使用者不輸入的情況下,只要頁面開啟,則應該長連線保持。

測試網址

127.0.0.1/index.php?id=1

主要程式碼

客戶端主要程式碼

客戶端程式碼主要在 index.php 中

window.onload = function() {
    activate_chat_js();

    var wsServer = 'ws://{$JS_IP}:9501';
    var websocket = new WebSocket(wsServer);
    window.websocket = websocket;
    websocket.onopen = function(evt) {
        console.log("Connected to WebSocket server.");
        heartCheck.reset().start(); //心跳檢測重置
        websocket.send("my_id|{$user_id}");
    };

    websocket.onclose = function(evt) {
        console.log("Disconnected");
    };

    websocket.onmessage = function(evt) {
        console.log('從伺服器接受的資料 ' + evt.data);
        // 心跳最前面檢測
        if (evt.data == 'pong') {
            heartCheck.reset().start(); //心跳檢測重置
            return;
        }


        var user = JSON.parse(evt.data);
        if (user.type == 'my_id') {
            system_chatWindow(user.message);
        }
        // v4.0修改。其他人接受某人的訊息廣播。
        if (user.type == 'my_message') {
            update_chatWindow2(user.message, user.from_user_name);
        }

    };

    websocket.onerror = function(evt, e) {
        console.log('Error occured: ' + evt.data);
    };

    var heartCheck = {
        timeout: 5000,
        //單位毫秒,5秒發一次心跳,改成61000,就是61秒就會被伺服器自動斷掉,
        // 說明,只需這個值大於 伺服器的heartbeat_idle_time 與 heartbeat_check_interval 的和,就一定會自動停掉。
        timeoutObj: null,
        serverTimeoutObj: null,
        reset: function() {
            clearTimeout(this.timeoutObj);
            clearTimeout(this.serverTimeoutObj);
            return this;
        },
        start: function() {
            var self = this;
            this.timeoutObj = setTimeout(function() {
                //這裡傳送一個心跳,後端收到後,返回一個心跳訊息,
                //onmessage拿到返回的心跳就說明連線正常
                websocket.send("ping");
                console.log("ping")

            }, this.timeout)
        }
    };

}

服務端主要程式碼

        $this->server = new \swoole_websocket_server(
            $this->config['socket']['host'],
            $this->config['socket']['port']
        );

        //v5.0 設定心跳檢測
        $this->server->set(array(
            'heartbeat_idle_time'      => 30, // 表示一個連線如果30秒內未向伺服器傳送任何資料,此連線將被強制關閉
            'heartbeat_check_interval' => 25,  // 表示每25秒遍歷一次
        ));
public function message(\swoole_websocket_server $server, \swoole_websocket_frame $frame)  {

        $data = $frame->data;
        echo "有訊息:".$data."\n";
        //這裡使用者發來的資訊已經分型別了。my_id開頭,說明是系統自動從客戶端傳送的資訊,用於識別身份。

        if (preg_match('#^ping#', $data)) {
            echo "心跳來了 " .date("Y-m-d H:i:s")."\n";
            $server->push($frame->fd,'pong');// 返回一個訊息,過會他會再次傳來。

        } elseif (preg_match('#^my_id#', $data)) {
            $user_id = explode("|", $data)[1];
            $arr = $this->user_all;
            $user_name = isset($arr[$user_id]) ? $arr[$user_id] : '';
        //。。。。。
        }
    }

WebSocketServer.php 是核心檔案。

程式碼說明

1、客戶端每隔多少秒傳送一次訊息給伺服器,防止伺服器斷長連線。
2、只需這個值大於 伺服器的heartbeat_idle_time 與 heartbeat_check_interval 的和,就一定會自動停掉。
3、保險起見,客戶端的定時的值,需要小於heartbeat_idle_time 值。
4、heartbeat_idle_time 表示伺服器發現某客戶端多長時間不聯絡伺服器,就主動斷
5、heartbeat_check_interval 表示伺服器每隔多長時間來檢測這個心跳。顯然應小於heartbeat_idle_time
6、客戶端在 onopen 和 onmessage 這兩個方法裡進行定時器設定,具體象打乒乓球,客戶端發出ping,伺服器立刻返回,客戶端間隔一定時間,再次ping,伺服器總是立刻返回。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章