使用swoole部署websocket服務端
Swoole 支持在同一個 WebSocket 服務中監聽多個端口,併為不同端口配置不同的協議(ws 或 wss)。只需在創建 Swoole\WebSocket\Server 時通過 addListener() 方法添加額外端口,並分別配置 SSL 證書即可。
方式一:直接起兩個服務端口(不推薦)
方式一實現示例代碼:
<?php
// 創建主服務器(默認不配置 SSL,作為 ws 服務)
$ws = new Swoole\WebSocket\Server("0.0.0.0", 9501);
// 為主服務器添加 SSL 配置的端口(9502 作為 wss 服務)
// 注意:第二個參數需指定 SWOOLE_SSL 標記
$ws->addListener("0.0.0.0", 9502, SWOOLE_SOCK_TCP | SWOOLE_SSL);
// 配置 SSL 證書(僅對 9502 端口生效)
$ws->set([
'ssl_cert_file' => __DIR__ . '/cert.pem', // SSL 證書文件路徑
'ssl_key_file' => __DIR__ . '/key.pem', // SSL 私鑰文件路徑
'worker_num' => 4, // 工作進程數
]);
// 監聽連接打開事件
$ws->on('Open', function ($ws, $request) {
// 可以通過 $request->fd 區分不同客户端
// 可以通過 $request->server['server_port'] 判斷客户端連接的端口
echo "客户端 {$request->fd} 連接成功,端口:{$request->server['server_port']}\n";
});
// 監聽消息事件
$ws->on('Message', function ($ws, $frame) {
// 向客户端回覆消息
$ws->push($frame->fd, "服務器收到:{$frame->data}");
echo "收到來自 fd={$frame->fd} 的消息:{$frame->data}\n";
});
// 監聽連接關閉事件
$ws->on('Close', function ($ws, $fd) {
echo "客户端 {$fd} 斷開連接\n";
});
// 啓動服務
$ws->start();
?>
關鍵説明:
-
多端口監聽:
- 主服務通過 new Swoole\WebSocket\Server("0.0.0.0", 9501) 監聽 9501 端口(默認不啓用 SSL,即 ws:// 服務)。
- 通過 addListener() 方法添加 9502 端口,並指定 SWOOLE_SSL 標記,使其成為 wss:// 服務。
-
SSL 配置:
- ssl_cert_file 和 ssl_key_file 需填寫正確的證書和私鑰路徑(自簽名證書可用於測試,生產環境需用可信 CA 證書)。
- SSL 配置會自動應用到帶有 SWOOLE_SSL 標記的端口(即 9502 端口),9501 端口不受影響。
-
客户端連接方式:
- 連接 9501 端口:ws://your_domain.com:9501
- 連接 9502 端口:wss://your_domain.com:9502
-
端口區分:
- 在事件回調中,可通過 $request->server['server_port'] 判斷客户端連接的是哪個端口(9501 或 9502),便於區分處理。
注意事項:
- 需確保服務器防火牆開放 9501 和 9502 端口。
- 生產環境中,建議通過 Nginx 反向代理 wss:// 到後端的 ws:// 服務(更便於證書管理和負載均衡),直接暴露多端口的場景較少。
這種方式可以在同一個 Swoole 服務中同時提供 ws 和 wss 兩種連接方式,適合需要同時支持明文和加密連接的場景。
方式二:通過nginx反向代理(推薦)
在生產環境中通過nginx反向代理, 可以讓後端 Swoole WebSocket 服務僅監聽 127.0.0.1:9501, 來同時實現對wss://和ws://兩種連接的支持.
具體實現方式
通過 Nginx 配置兩條代理規則,分別處理 wss://(加密)和 ws://(明文)連接,最終都轉發到後端同一個 ws://127.0.0.1:9501 服務。
示例nginx配置:
server {
# 同時監聽 80 端口(HTTP/ws)和 443 端口(HTTPS/wss)
listen 80;
listen 443 ssl;
server_name your_domain.com;
# SSL 證書配置(僅對 443 端口生效)
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# 處理 WebSocket 代理(同時支持 ws 和 wss)
location /ws {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 轉發到後端同一個 ws 服務
proxy_pass http://127.0.0.1:9501;
}
}
後端Swoole服務配置:
只需監聽本地 127.0.0.1:9501(不暴露公網,僅通過 Nginx 代理訪問):
$ws = new Swoole\WebSocket\Server("127.0.0.1", 9501); // 僅監聽本地端口
// ... 事件回調配置 ...
$ws->start();
這裏nginx是通過location的/ws進行匹配的
因此如下的請求地址可以匹配到/ws中的規則並將連接進行升級
ws:/your-domain/ws
wss://your-domain/ws
http:/your-domain/ws
而直接使用下面的連接是不能直接進行匹配並升級成websocket連接的
ws://your-domain
wss://your-domain
核心原理
-
wss://連接流程:
- 客户端發起 wss://your_domain.com/ws 連接 → 經過 Nginx 443 端口。
- Nginx 用 SSL 證書解密 → 將明文數據轉發到 ws://127.0.0.1:9501。
- 後端 Swoole 服務處理明文 ws 數據,響應通過 Nginx 加密後返回給客户端。
-
ws:// 連接流程:
- 客户端發起 ws://your_domain.com/ws 連接 → 經過 Nginx 80 端口。
- Nginx 直接將明文數據轉發到 ws://127.0.0.1:9501。
- 後端 Swoole 服務直接處理並響應。
優勢
- 後端簡化:只需維護一個 ws 服務,無需處理 SSL 證書,降低複雜度。
- 安全可控:後端服務僅監聽本地端口,不直接暴露公網,通過 Nginx 統一入口管理。
- 靈活擴展:未來如需調整端口或增加負載均衡,僅需修改 Nginx 配置,無需改動後端服務。
注意事項
- 若需要禁止 ws:// 明文連接(僅允許 wss://),可刪除 80 端口的 Nginx 配置,或在 80 端口配置中將 ws:// 請求重定向到 wss://。
- 確保 Nginx 的 proxy_pass 路徑與後端服務的監聽地址一致(如均為 9501 端口)。