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