使用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 端口)。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。