PHP项目怎么使用WebSocket?

wen java案例 2

本文目录导读:

PHP项目怎么使用WebSocket?

  1. 使用专门的WebSocket库(推荐)
  2. 运行WebSocket服务器
  3. 与现有PHP项目集成
  4. 完整项目示例
  5. 注意事项
  6. 选择建议

在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)作为中间件。

抱歉,评论功能暂时关闭!