本文目录导读:

在PHP项目中使用WebSocket,主要有两种方式:
使用专门的WebSocket库(推荐)
Ratchet(最流行)
composer require cboden/ratchet
服务器端示例 (server.php):
<?php
require __DIR__ . '/vendor/autoload.php';
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 "New connection: {$conn->resourceId}\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
foreach ($this->clients as $client) {
if ($from !== $client) {
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "Error: {$e->getMessage()}\n";
$conn->close();
}
}
// 启动服务器
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
8080
);
echo "WebSocket server started on port 8080\n";
$server->run();
客户端JS代码:
const ws = new WebSocket('ws://localhost:8080');
ws.onopen = function() {
console.log('Connected');
ws.send('Hello server!');
};
ws.onmessage = function(event) {
console.log('Received:', event.data);
};
ws.onclose = function() {
console.log('Disconnected');
};
Swoole(高性能)
pecl install swoole
服务器端示例:
<?php
$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);
$server->on('open', function($server, $request) {
echo "New connection: {$request->fd}\n";
});
$server->on('message', function($server, $frame) {
echo "Received: {$frame->data}\n";
foreach ($server->connections as $fd) {
$server->push($fd, $frame->data);
}
});
$server->on('close', function($server, $fd) {
echo "Connection {$fd} closed\n";
});
echo "WebSocket server started on port 9501\n";
$server->start();
运行WebSocket服务器
方式1:直接运行
php server.php
方式2:作为守护进程
使用Supervisor管理(生产环境推荐):
[program:websocket] command=php /path/to/server.php autostart=true autorestart=true user=www-data
与现有PHP项目集成
场景1:需要认证的用户
// 服务器端验证token
public function onOpen(ConnectionInterface $conn) {
$queryString = $conn->httpRequest->getUri()->getQuery();
parse_str($queryString, $params);
if (!authenticateToken($params['token'])) {
$conn->close();
return;
}
$this->clients[$params['user_id']] = $conn;
}
场景2:向特定用户发送消息
// 从Web服务器触发WebSocket消息
function sendToUser($userId, $message) {
$client = new WebSocket\Client("ws://localhost:8080");
$client->send(json_encode([
'type' => 'direct',
'to' => $userId,
'data' => $message
]));
}
完整项目示例
Laravel + Ratchet
// 创建Artisan命令
php artisan make:command WebSocketServer
// app/Console/Commands/WebSocketServer.php
class WebSocketServer extends Command
{
protected $signature = 'websocket:serve';
public function handle()
{
$server = IoServer::factory(
new HttpServer(
new WsServer(
new ChatController()
)
),
8080
);
$server->run();
}
}
注意事项
性能优化
- 使用事件驱动而非进程/线程
- 避免在回调中执行长时间操作
- 考虑使用Redis等消息队列解耦
安全性
// 验证来源
$origin = $conn->httpRequest->getHeader('Origin');
if (!in_array($origin, ['https://yourdomain.com'])) {
$conn->close();
return;
}
// 消息格式验证
$data = json_decode($msg, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$conn->send(json_encode(['error' => 'Invalid JSON']));
return;
}
连接管理
// 心跳检测(每30秒)
$server->on('open', function($conn) use ($loop) {
$conn->lastHeartbeat = time();
$loop->addPeriodicTimer(30, function() use ($conn) {
if (time() - $conn->lastHeartbeat > 60) {
$conn->close();
}
$conn->send(json_encode(['type' => 'ping']));
});
});
选择建议
| 场景 | 推荐方案 |
|---|---|
| 简单聊天应用 | Ratchet |
| 高并发实时系统 | Swoole |
| 与Laravel集成 | Laravel WebSocket |
| 微服务架构 | 考虑使用Centrifugo |
| 需要SSL支持 | Ratchet + SSL |
最佳实践:小型项目使用Ratchet,大型高并发项目使用Swoole,如果需要更好的扩展性,可以考虑使用专门的WebSocket服务(如Pusher、Centrifugo)作为中间件。