本文目录导读:

PHP 双工模式(双向通信)通常指在单个连接上实现客户端和服务器之间的实时、双向数据交换,在 PHP 生态中,常见的实现方式有 WebSocket、SSE、Long Polling 和 PHP 与 Node.js/Go 混合 模式。
这里重点介绍 基于 WebSocket 的双工模式设计,因为这是 PHP 中最正宗、最常用的双工通信方案。
核心设计思路
双工模式 = 一个长连接 + 双方都能主动推送数据。
PHP 传统是“请求-响应”模式(短连接),要实现双工,必须使用事件驱动或非阻塞模型,并配合 WebSocket 协议。
三种主流实现方案
使用 Swoole 或 Workerman(推荐)
这是 PHP 实现双工最成熟、性能最高的方式,Swoole/Workerman 是常驻内存的 PHP 扩展或框架,原生支持 WebSocket 协议。
设计示例(Workerman):
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
// 1. 创建 WebSocket 服务器(监听 8080 端口)
$ws_worker = new Worker('websocket://0.0.0.0:8080');
// 2. 定义连接数量(控制并发)
$ws_worker->count = 4; // 4个进程
// 3. 当客户端连接时触发
$ws_worker->onConnect = function(TcpConnection $connection) {
echo "新连接: {$connection->id}\n";
};
// 4. 当收到客户端消息时触发(服务端可以回复,实现双工)
$ws_worker->onMessage = function(TcpConnection $connection, $data) {
echo "收到: {$data}\n";
// 双工:服务器可以主动推送消息(不仅限于回复)
$connection->send('服务器主动推送:时间戳 ' . time());
// 也可以广播给所有连接
foreach ($connection->worker->connections as $conn) {
$conn->send("用户 {$connection->id} 说: {$data}");
}
};
// 5. 当连接关闭时触发
$ws_worker->onClose = function(TcpConnection $connection) {
echo "连接关闭: {$connection->id}\n";
};
Worker::runAll();
运行方法:
php server.php start
方案优势:
- 真正的全双工(双方随时发消息)
- 支持高并发(异步非阻塞)
- 自带心跳检测、断线重连处理
使用 ReactPHP + Ratchet(纯 PHP 协程)
如果不想安装 Swoole/Workerman 扩展,可以使用纯 PHP 的协程库 ReactPHP 配合 Ratchet。
// composer require cboden/ratchet
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
class Chat implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo "新连接: {$conn->resourceId}\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
// 双工逻辑:服务器可以广播消息
foreach ($this->clients as $client) {
if ($from !== $client) {
$client->send("用户 {$from->resourceId} 说: {$msg}");
}
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo "连接关闭\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
$conn->close();
}
}
// 启动服务器
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
8080
);
$server->run();
通过 PHP-FPM + Redis 发布订阅 + 轮询(伪双工)
如果无法使用长驻进程,可以模拟双工:
- 客户端:通过 WebSocket 连接到一个轻量级服务(如 Node.js)
- PHP 后端:接收到 HTTP 请求后,写入 Redis 队列
- Node.js 服务:订阅 Redis,收到消息后通过 WebSocket 推送给客户端
[浏览器] <--WebSocket--> [Node.js 网关] <--Redis--> [PHP 后端]
这种方式 PHP 依然是“请求-响应”,但整体系统实现了双工。
双工模式设计的关键要点
| 要点 | 说明 |
|---|---|
| 心跳机制 | 每 30-60 秒发送 ping/pong,检测死连接 |
| 消息编码 | 使用 JSON 或 Protocol Buffers,包含 type、data、from 等字段 |
| 身份认证 | 连接建立时通过 Token 验证,避免未授权访问 |
| 消息确认 | 对于重要消息,客户端需返回 ACK,服务端未收到则重发 |
| 断线重连 | 客户端实现自动重连,服务端记录会话状态 |
| 并发控制 | 使用 Swoole/Workerman 的进程模型,避免阻塞 |
示例:WebSocket 双工消息格式
// 客户端 -> 服务端
{
"type": "message",
"payload": {
"to": "user_123",
"content": "你好",
"timestamp": 1715000000
},
"token": "xxx"
}
// 服务端 -> 客户端
{
"type": "broadcast",
"payload": {
"from": "user_456",
"content": "大家好",
"timestamp": 1715000100
}
}
// 服务端 -> 单个客户端(认证成功)
{
"type": "auth_success",
"payload": {
"user_id": "user_123",
"online_count": 42
}
}
// 心跳
{
"type": "ping"
}
// 回复
{
"type": "pong"
}
选择建议
| 场景 | 推荐方案 |
|---|---|
| 高并发实时聊天/游戏 | Swoole(性能最好) |
| 中等规模即时通讯 | Workerman(易用性好) |
| 不想装扩展,纯 PHP | ReactPHP + Ratchet |
| 已有 Node.js 基础设施 | Node.js 网关 + PHP 后端(混合) |
| 简单单向推送(服务器到客户端) | SSE(简单,但非双工) |
PHP 实现双工模式的本质是:
- 放弃短连接,使用长连接(WebSocket / SSE)
- 让 PHP 常驻内存(Swoole/Workerman)或借助中间件(Redis + Node.js)
- 在 onMessage 回调中实现“客户端发消息 → 服务端处理并主动推送”
推荐从 Workerman 开始,因为它:
- 文档丰富,中文友好
- 安装简单(
composer require workerman/workerman) - 性能足够 90% 的 PHP 双工场景
如果你需要具体的代码示例或调试建议,可以告诉我你的具体场景(如聊天、游戏、协作编辑等),我可以提供更针对性的设计。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播