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的边界远比你想象的宽广。

相关推荐
两个人的幸福3 天前
Windows 桌面应用自研 PHP 队列(下):完整代码与六大工程化优化
php
anOnion3 天前
构建无障碍组件之Menu Button pattern
前端·html·交互设计
米丘4 天前
微前端之 Web Components 完全指南
微服务·html
BingoGo5 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
JaguarJack5 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
用户3074596982076 天前
PHP 扩展——从入门到理解
php
鹏仔先生7 天前
拷贝漫画APP下载页PHP程序,后台带免费AI写作
php
LDR0067 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术7 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript
码云数智-园园7 天前
C++20 Modules 模块详解
java·开发语言·spring