PHP与WebSocket实时通信的原理到生产级应用

在传统HTTP协议下,服务器只能被动响应客户端的请求。要实现实时推送------比如聊天消息、股票行情、系统通知------通常需要客户端轮询,效率低、延迟高。

WebSocket的出现改变了这一局面,它让服务器可以主动向客户端推送数据。2026年的今天,WebSocket已经成为实时Web应用的标准技术。PHP能玩WebSocket吗?当然能。而且用对了工具,PHP在实时通信领域同样表现惊艳。

一、WebSocket基础:为什么需要它?

1.1 HTTP的短板

HTTP是无状态、单向的协议。客户端发起请求,服务器返回响应,然后连接关闭。要实现"服务器主动通知",只能用轮询(频繁发请求)、长轮询(连接挂起)或Server-Sent Events(SSE)。这些方案要么浪费资源,要么单向,要么延迟高。

1.2 WebSocket的原理

WebSocket在HTTP握手后,升级为长连接,全双工通信。客户端和服务端可以随时互发消息,开销小、实时性强。

握手示例(客户端请求):

bash 复制代码
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13

服务器响应:

bash 复制代码
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

之后,双方通过帧(Frame)传输数据,不包含HTTP头部,效率极高。

二、PHP中的WebSocket方案选择

PHP有几种方式实现WebSocket:

  • Swoole:C扩展,高性能协程,内置WebSocket服务器。

  • Workerman:纯PHP实现,稳定易用,文档丰富。

  • ReactPHP + Ratchet:基于ReactPHP的事件驱动,纯PHP,适合学习。

生产环境中,Swoole和Workerman是主流。本文主要介绍Swoole和Workerman两种方式,并对比适用场景。

三、基于Swoole的WebSocket服务器

Swoole 4.0+ 原生支持WebSocket,且性能极高。

3.1 安装

bash 复制代码
pecl install swoole

3.2 一个简单的聊天室

php 复制代码
<?php
// ws_server.php
$server = new Swoole\WebSocket\Server('0.0.0.0', 9502);

// 监听连接打开事件
$server->on('open', function ($server, $req) {
    echo "新连接: {$req->fd}\n";
    // 可以给新连接发送欢迎消息
    $server->push($req->fd, json_encode([
        'type' => 'system',
        'message' => '欢迎加入聊天室'
    ]));
});

// 监听消息接收事件
$server->on('message', function ($server, $frame) {
    echo "收到消息: {$frame->data}\n";
    // 广播给所有其他连接
    foreach ($server->connections as $fd) {
        // 不发给发送者自己
        if ($fd !== $frame->fd) {
            $server->push($fd, json_encode([
                'type' => 'message',
                'from' => $frame->fd,
                'data' => $frame->data
            ]));
        }
    }
});

// 监听连接关闭事件
$server->on('close', function ($server, $fd) {
    echo "连接关闭: {$fd}\n";
    // 通知其他用户
    foreach ($server->connections as $otherFd) {
        if ($otherFd !== $fd) {
            $server->push($otherFd, json_encode([
                'type' => 'system',
                'message' => "用户{$fd}离开了"
            ]));
        }
    }
});

$server->start();

3.3 协程风格的WebSocket客户端

Swoole还提供了协程客户端,可以方便地连接其他WebSocket服务。

php 复制代码
<?php
Swoole\Runtime::enableCoroutine();
go(function () {
    $client = new Swoole\Coroutine\Http\Client('ws.example.com', 80);
    $client->upgrade('/chat');
    $client->push(json_encode(['msg' => 'Hello']));
    $response = $client->recv();
    echo "收到: $response\n";
    $client->close();
});

3.4 与HTTP服务共存

Swoole的WebSocket服务器也可以处理HTTP请求,可以共用同一个端口。

php 复制代码
$server = new Swoole\WebSocket\Server('0.0.0.0', 9502);
// 处理HTTP请求
$server->on('request', function ($req, $resp) {
    $resp->end('HTTP部分');
});
// 处理WebSocket
$server->on('message', function ($server, $frame) { ... });

四、基于Workerman的WebSocket服务器

Workerman是纯PHP实现的高性能框架,支持WebSocket、TCP、UDP等协议。

4.1 安装

bash 复制代码
composer require workerman/workerman

4.2 聊天室实现

php 复制代码
<?php
// ws_worker.php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;

require_once __DIR__ . '/vendor/autoload.php';

$ws_worker = new Worker('websocket://0.0.0.0:9503');

$ws_worker->count = 4; // 开启4个进程

$ws_worker->onConnect = function(TcpConnection $connection) {
    echo "新连接: {$connection->id}\n";
    $connection->send(json_encode([
        'type' => 'system',
        'message' => '欢迎加入聊天室'
    ]));
};

$ws_worker->onMessage = function(TcpConnection $connection, $data) use ($ws_worker) {
    echo "收到消息: $data\n";
    // 广播给所有连接
    foreach ($ws_worker->connections as $client) {
        if ($client !== $connection) {
            $client->send(json_encode([
                'type' => 'message',
                'from' => $connection->id,
                'data' => $data
            ]));
        }
    }
};

$ws_worker->onClose = function(TcpConnection $connection) use ($ws_worker) {
    echo "连接关闭: {$connection->id}\n";
    foreach ($ws_worker->connections as $client) {
        $client->send(json_encode([
            'type' => 'system',
            'message' => "用户{$connection->id}离开了"
        ]));
    }
};

Worker::runAll();

4.3 Workerman的优缺点

优点

  • 纯PHP,无需扩展,兼容性好。

  • 文档详尽,社区活跃。

  • 支持多进程、多协议混合。

缺点

  • 性能略低于Swoole。

  • 协程支持需要额外库(如webman)。

五、前端JavaScript连接WebSocket

无论后端用Swoole还是Workerman,前端代码是一样的。

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>WebSocket聊天室</title>
</head>
<body>
    <input type="text" id="message" placeholder="输入消息">
    <button onclick="send()">发送</button>
    <div id="messages"></div>

    <script>
        // 创建连接
        const ws = new WebSocket('ws://your-server-ip:9502');

        ws.onopen = function() {
            console.log('连接已建立');
            addMessage('系统', '已连接到聊天室');
        };

        ws.onmessage = function(event) {
            const data = JSON.parse(event.data);
            addMessage(data.type === 'system' ? '系统' : '用户', data.message || data.data);
        };

        ws.onclose = function() {
            console.log('连接关闭');
            addMessage('系统', '连接已断开');
        };

        function send() {
            const input = document.getElementById('message');
            const msg = input.value;
            if (msg) {
                ws.send(msg);
                input.value = '';
            }
        }

        function addMessage(from, text) {
            const div = document.getElementById('messages');
            const p = document.createElement('p');
            p.innerHTML = `<strong>${from}:</strong> ${text}`;
            div.appendChild(p);
        }
    </script>
</body>
</html>

六、进阶实战:带用户认证的WebSocket

在生产环境中,WebSocket连接需要认证用户身份。通常做法是在HTTP握手时传递token。

6.1 Swoole中认证

php 复制代码
$server->on('open', function ($server, $req) {
    $token = $req->get['token'] ?? '';
    $user = authenticate($token);
    if (!$user) {
        $server->disconnect($req->fd, 1000, '认证失败');
        return;
    }
    // 存储用户信息到连接上下文
    $server->push($req->fd, json_encode(['type' => 'auth', 'status' => 'success']));
});

6.2 Workerman中认证

Workerman需要在onWebSocketConnect回调中处理:

php 复制代码
$ws_worker->onWebSocketConnect = function($connection, $http_header) {
    // 解析URL参数
    $query = parse_url($http_header['request_uri'], PHP_URL_QUERY);
    parse_str($query, $params);
    $token = $params['token'] ?? '';
    $user = authenticate($token);
    if (!$user) {
        $connection->close();
    }
    $connection->user = $user;
};

七、消息推送与业务解耦

WebSocket服务器通常只负责连接管理,业务逻辑(如消息存储、离线推送)可以交给后端处理。一个常见模式是:业务后端通过Redis发布消息,WebSocket服务器订阅并推送给用户。

php 复制代码
// 业务代码中,当有新消息时
$redis->publish('user:123', json_encode(['msg' => '新订单来了']));

// WebSocket服务器订阅
$server->on('message', ...); // 原有处理
// 新加一个Redis订阅协程
go(function () use ($server) {
    $redis = new Swoole\Coroutine\Redis();
    $redis->connect('127.0.0.1', 6379);
    $redis->subscribe(['user:123', 'user:456']);
    while (true) {
        $msg = $redis->recv();
        // 解析目标用户,推送给对应连接
        // 这里需要维护 fd 和 user_id 的映射
    }
});

八、性能与运维

  • 进程数:Swoole和Workerman都支持多进程,通常设置为CPU核数的1-4倍。

  • 连接数:单机可支撑几十万连接,但需要调整Linux系统参数(ulimit -n、net.ipv4.tcp_tw_reuse等)。

  • 心跳:WebSocket有Ping/Pong帧,可定期发送检测连接活跃,及时清理僵尸连接。

  • SSL:WebSocket over TLS(wss)可通过配置SSL证书实现。

九、Swoole vs Workerman:选型建议

维度 Swoole Workerman
安装 C扩展,需要编译 Composer包,纯PHP
性能 极高(协程) 高(多进程)
协程 原生支持 需第三方库(如webman)
调试 较难(Xdebug有限制) 容易(常规PHP)
学习曲线 较陡 平缓
适用场景 高并发、微服务、网关 传统WebSocket应用、实时推送

建议

  • 如果是新项目,追求极致性能,且运维可以装扩展,选Swoole。

  • 如果是老项目,不能装扩展,或团队对协程不熟悉,选Workerman。

十、总结

WebSocket为PHP打开了实时通信的大门。无论是Swoole还是Workerman,都能让你用熟悉的语言构建高性能的实时应用。

  • 聊天室、直播弹幕、实时数据看板、在线客服、游戏服务器......这些场景PHP都能胜任。

  • 配合消息队列、Redis等组件,还能实现离线推送、消息持久化、多端同步等高级功能。

如果你还没尝试过PHP + WebSocket,不妨从今天开始,用几行代码写一个简单的聊天室,感受一下实时通信的魅力。你会发现,PHP的边界远比你想象的宽广。

相关推荐
宝耶2 小时前
Java面试2:final、finally、finalize 的区别?
java·开发语言·面试
码云数智-大飞2 小时前
生死时速:高并发秒杀系统的架构设计与防超卖实战
开发语言
DREW_Smile2 小时前
数据在内存中的存储
c语言·开发语言
吴声子夜歌2 小时前
JavaScript——对象
开发语言·javascript·ecmascript
uimaker3 小时前
uimaker响应式jQuery Easyui+Bootstrap多配色主题设计
前端框架·bootstrap·html·jquery·easyui·后台模版
比昨天多敲两行3 小时前
C++ 继承
开发语言·c++·面试
不会写DN3 小时前
Js常用的字符串处理
开发语言·前端·javascript
dreamxian3 小时前
苍穹外卖day10
java·开发语言·spring boot
2501_908329853 小时前
C++中的装饰器模式实战
开发语言·c++·算法