使用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();
?>

关键说明:

  1. 多端口监听:

    • 主服务通过 new Swoole\WebSocket\Server("0.0.0.0", 9501) 监听 9501 端口(默认不启用 SSL,即 ws:// 服务)。
    • 通过 addListener() 方法添加 9502 端口,并指定 SWOOLE_SSL 标记,使其成为 wss:// 服务。
  2. SSL 配置:

    • ssl_cert_file 和 ssl_key_file 需填写正确的证书和私钥路径(自签名证书可用于测试,生产环境需用可信 CA 证书)。
    • SSL 配置会自动应用到带有 SWOOLE_SSL 标记的端口(即 9502 端口),9501 端口不受影响。
  3. 客户端连接方式:

    • 连接 9501 端口:ws://your_domain.com:9501
    • 连接 9502 端口:wss://your_domain.com:9502
  4. 端口区分:

    • 在事件回调中,可通过 $request->server['server_port'] 判断客户端连接的是哪个端口(9501 或 9502),便于区分处理。

注意事项:

  1. 需确保服务器防火墙开放 9501 和 9502 端口。
  2. 生产环境中,建议通过 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

核心原理

  1. wss://连接流程:

    • 客户端发起 wss://your_domain.com/ws 连接 → 经过 Nginx 443 端口。
    • Nginx 用 SSL 证书解密 → 将明文数据转发到 ws://127.0.0.1:9501。
    • 后端 Swoole 服务处理明文 ws 数据,响应通过 Nginx 加密后返回给客户端。
  2. 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 端口)。

daoheng
1 声望0 粉丝

活到老,学到老