環境需求
- PHP 7.1+
- Swoole 擴充套件
pecl install swoole(需啟用 --enable-openssl --enable-http2 --enable-websocket)
核心程式碼
<?php
define('DEBUG', 'on');
define('WEBPATH', str_replace('\\', '/', __DIR__));
require __DIR__ . '/../libs/lib_config.php';
class WebSocket extends Swoole\WebSocket\Server {
// 客戶端斷線
public function onClose($server, $fd, $reactorId) {
// 可選:廣播下線通知
// $this->broadcast("User {$fd} left");
parent::onClose($server, $fd, $reactorId);
}
// 收到訊息
public function onMessage($server, $frame) {
$this->log("onMessage: fd={$frame->fd} data={$frame->data}");
// 回覆發送者
$this->push($frame->fd, "Server: {$frame->data}");
// 廣播給其他人(取消註解啟用)
// foreach ($this->connections as $fd) {
// if ($fd != $frame->fd) $this->push($fd, "User {$frame->fd}: {$frame->data}");
// }
}
}
$server = new WebSocket('0.0.0.0', 9503);
$server->set([
'worker_num' => 4,
'daemonize' => false, // 除錯時設 false
'log_file' => WEBPATH . '/swoole.log',
]);
$server->start();
架構說明
- 繼承
Swoole\WebSocket\Server:自動處理 WebSocket 握手、幀解析、心跳等協定細節。
- onMessage 回傳
$frame 物件:包含 fd (客戶端 ID)、data (訊息內容)、opcode (文字/二進位)、finish (是否為最後一幀)。
$this->connections:陣列保存所有連線 fd,可直接遍歷廣播。
- Worker 多進程:
worker_num => 4 啟動 4 個 Worker 進程,利用多核心。Swoole 內部用 Round-Robin 分發連線。
前端測試頁面
<!DOCTYPE html>
<html>
<script>
var ws = new WebSocket("ws://your-server-ip:9503");
ws.onopen = () => console.log("已連線");
ws.onmessage = e => console.log("收到:", e.data);
ws.onclose = () => console.log("斷線");
function send() { ws.send(document.getElementById('msg').value); }
</script>
<input id="msg" placeholder="輸入訊息">
<button onclick="send()">發送</button>
</html>
生產環境強化清單
- SSL/WSS:
ssl_cert_file, ssl_key_file 設定憑證,啟用 open_websocket_close_frame。
- 心跳檢測:
heartbeat_check_interval, heartbeat_idle_time 自動清理殭屍連線。
- 訊息佇列:大量廣播時改用
Swoole\Coroutine\Channel 或 Redis Pub/Sub 解耦。
- 身份驗證:握手階段
onHandshake 驗證 Token/JWT,拒絕非法連線。
- 監控指標:連線數、QPS、記憶體、CPU,接入 Prometheus/Grafana。