首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

使用 PHP Swoole 實現簡單的多人線上聊天廣播功能

     編輯:PHP 相關知識

使用 PHP Swoole 實現簡單的多人線上聊天廣播功能

本文將示範如何利用 PHP 的 Swoole 擴展,快速構建一個基於 WebSocket 的多人線上聊天室,核心功能為訊息廣播。雖然未實現完整的聊天邏輯細節(如私聊、房間管理、用戶列表等),但作為入門範例足以展示 Swoole 處理高併發長連接的強大能力。

伺服器端核心代碼 (PHP)

我們建立一個 WebSocket 伺服器,監聽 127.0.0.1:3999,並配置多進程模型以提升效能。

$serv = new swoole_websocket_server("127.0.0.1", 3999);

// 伺服器基礎配置
$serv->set(array(
    'worker_num'      => 2,           // Worker 進程數
    'reactor_num'     => 8,           // Reactor 線程數
    'task_worker_num' => 1,           // Task 工作進程數
    'dispatch_mode'   => 2,           // 固定模式分發
    'debug_mode'      => 1,           // 除錯模式
    'daemonize'       => true,        // 守護進程模式
    'log_file'        => __DIR__.'/log/webs_swoole.log',
    'heartbeat_check_interval' => 60, // 心跳檢測間隔
    'heartbeat_idle_time'      => 600 // 心跳最大閒置時間
));

// 連接建立事件
$serv->on('connect', function ($serv, $fd) {
    // echo "client:$fd Connect.\n";
});

// 接收資料事件 (WebSocket 通常使用 onMessage)
$serv->on("receive", function(swoole_server $serv, $fd, $from_id, $data) {
    // echo "receive#{$from_id}: receive $data \n";
});

// WebSocket 握手成功事件
$serv->on('open', function($server, $req) {
    // echo "server#{$server->worker_pid}: handshake success with fd#{$req->fd}\n";
});

// 接收客戶端訊息事件
$serv->on('message', function($server, $frame) {
    // echo "message: ".$frame->data."\n";
    $msg = json_decode($frame->data, true);
    
    switch ($msg['type']) {
        case 'login':
            $server->push($frame->fd, "歡迎歡迎~");
            break;
        default:
            break;
    }
    
    // 將發送者 fd 附加到訊息中,交由 Task 工作進程處理廣播邏輯
    $msg['fd'] = $frame->fd;
    $server->task($msg);
});

// Worker 進程啟動事件
$serv->on("workerstart", function($server, $workerid) {
    // echo "workerstart: ".$workerid."\n";
});

// 註冊 Task 回調
$serv->on("task", "on_task");
$serv->on("finish", function($serv, $task_id, $data) {
    return;
});

// 連接關閉事件
$serv->on('close', function($server, $fd, $from_id) {
    // echo "connection close: ".$fd."\n";
});

$serv->start();

// Task 任務處理函數:負責廣播訊息給所有連接
function on_task($serv, $task_id, $from_id, $data) {
    switch ($data['type']) {
        case 'login':
            $send_msg = "說:我來了~";
            break;
        default:
            $send_msg = "說:{$data['msg']['speak']}";
            break;
    }
    
    // 遍歷所有連接進行廣播
    foreach ($serv->connections as $conn) {
        if ($conn != $data['fd']) {
            // 遊客名稱加上 fd 區分
            if (strpos($data['msg']['name'], "遊客") === 0) {
                $name = $data['msg']['name'] . "_" . $data['fd'];
            } else {
                $name = $data['msg']['name'];
            }
        } else {
            $name = "我";
        }
        $serv->push($conn, $name . $send_msg);
    }
    return;
}

function on_finish($serv, $task_id, $data) {
    return true;
}

前端頁面代碼 (HTML + JavaScript)

簡單的 WebSocket 客戶端頁面,包含暱稱輸入、訊息發送、聊天記錄顯示區域。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>WebSocket 聊天測試</title>
    <script src="jquery-1.12.0.min.js"></script>
</head>
<body>
    <h2>WebSocket Test</h2>
    暱稱:<input type="text" id="name" size="5" value="遊客"/>
    <input type="text" id="content" placeholder="輸入訊息">
    <button onclick="speak_to_all()">發送</button>
    <br/><br/>
    <textarea id="message" rows="10" cols="50" readonly></textarea>
    <div id="output"></div>
</body>
<script>
    var wsUri = "ws://127.0.0.1:3999/";
    var output;
    var websocket;

    function init() {
        output = document.getElementById("output");
        testWebSocket();
    }

    function testWebSocket() {
        websocket = new WebSocket(wsUri);
        websocket.onopen = function(evt) { onOpen(evt) };
        websocket.onclose = function(evt) { onClose(evt) };
        websocket.onmessage = function(evt) { onMessage(evt) };
        websocket.onerror = function(evt) { onError(evt) };
    }

    function get_speak_msg() {
        var name = document.getElementById("name").value;
        var speak = document.getElementById("content").value;
        return JSON.stringify({name: name, speak: speak});
    }

    function pack_msg(type, msg) {
        return JSON.stringify({type: type, msg: JSON.parse(msg)});
    }

    function onOpen(evt) {
        append_speak("已連接到伺服器.........");
        var speak_msg = get_speak_msg();
        var send_msg = pack_msg("login", speak_msg);
        doSend(send_msg);
    }

    function onClose(evt) {
        append_speak("連線已斷開!");
    }

    function onMessage(evt) {
        append_speak(evt.data);
    }

    function onError(evt) {
        console.error(evt);
        alert("發生錯誤: " + evt.data);
    }

    function doSend(message) {
        websocket.send(message);
    }

    function append_speak(new_msg) {
        var textarea = document.getElementById("message");
        textarea.value += new_msg + "\n";
        textarea.scrollTop = textarea.scrollHeight;
    }

    function speak_to_all() {
        var content = document.getElementById("content").value;
        if (content === "") return;
        
        var send_msg = pack_msg("speak", get_speak_msg());
        doSend(send_msg);
        document.getElementById("content").value = "";
    }

    init();
</script>
</html>

關鍵點解析

  • 多進程架構:Swoole 透過 Reactor、Worker、TaskWorker 多層進程模型,充分利用多核 CPU,實現高併發。
  • Task 異步任務:將廣播邏輯放入 Task 工作進程,避免阻塞 Worker 處理新請求。
  • 連接管理:使用 `$serv->connections` 獲取所有活躍連接 FD,實現廣播。
  • 心跳機制:配置 `heartbeat_check_interval` 和 `heartbeat_idle_time` 自動清理死連接。

運行步驟

  1. 確保 PHP 環境已安裝 Swoole 擴展 (PECL install swoole)。
  2. 將伺服器代碼保存為 server.php,前端代碼保存為 index.html。
  3. 終端執行 php server.php 啟動服務。
  4. 瀏覽器打開 index.html (建議通過本地 Web 服務器如 Nginx/Apache 訪問,避免跨域問題)。
  5. 多開幾個瀏覽器標籤頁測試廣播效果。

這個簡單的 Demo 為進一步開發功能完善的即時通訊系統奠定了基礎,後續可擴展用戶認證、房間分組、離線訊息、歷史記錄等功能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved