PHP 怎么WebSocket服务

wen PHP项目 2

本文目录导读:

PHP 怎么WebSocket服务

  1. 使用 Workerman(推荐)
  2. 使用 Ratchet
  3. 原生 PHP WebSocket 实现
  4. 客户端示例(JavaScript)
  5. 推荐方案对比
  6. 部署注意事项

在 PHP 中实现 WebSocket 服务有几种方式,下面我来详细介绍。

使用 Workerman(推荐)

Workerman 是最流行的 PHP WebSocket 解决方案。

安装

composer require workerman/workerman

基本示例

<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
// 创建 WebSocket 服务,监听 2346 端口
$ws_worker = new Worker("websocket://0.0.0.0:2346");
// 设置进程数
$ws_worker->count = 4;
// 客户端连接时触发
$ws_worker->onConnect = function(TcpConnection $connection) {
    echo "新连接建立\n";
};
// 收到客户端消息时触发
$ws_worker->onMessage = function(TcpConnection $connection, $data) {
    echo "收到消息: $data\n";
    // 发送消息给客户端
    $connection->send("服务器收到: $data");
    // 广播给所有客户端
    foreach ($connection->worker->connections as $client) {
        $client->send("广播消息: $data");
    }
};
// 客户端断开时触发
$ws_worker->onClose = function(TcpConnection $connection) {
    echo "连接关闭\n";
};
// 启动服务
Worker::runAll();

运行方式

# 启动服务(前台运行)
php websocket.php start
# 后台运行
php websocket.php start -d
# 停止服务
php websocket.php stop

使用 Ratchet

Ratchet 是另一个常用的 WebSocket 库。

安装

composer require cboden/ratchet

基本示例

<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
require_once __DIR__ . '/vendor/autoload.php';
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) {
        echo "收到消息: $msg\n";
        // 广播给所有客户端
        foreach ($this->clients as $client) {
            if ($from !== $client) {
                $client->send($msg);
            }
        }
    }
    // 关闭连接
    public function onClose(ConnectionInterface $conn) {
        $this->clients->detach($conn);
        echo "连接关闭\n";
    }
    // 错误处理
    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "错误: {$e->getMessage()}\n";
        $conn->close();
    }
}
// 创建服务
$server = IoServer::factory(
    new HttpServer(
        new WsServer(
            new Chat()
        )
    ),
    8080
);
echo "WebSocket 服务器运行在端口 8080\n";
$server->run();

运行方式

php chat-server.php

原生 PHP WebSocket 实现

如果不想使用第三方库,也可以原生实现(比较复杂):

<?php
class WebSocketServer {
    private $clients = [];
    private $socket;
    public function __construct($host, $port) {
        $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 1);
        socket_bind($this->socket, $host, $port);
        socket_listen($this->socket);
        echo "WebSocket 服务器运行在 $host:$port\n";
    }
    public function run() {
        while (true) {
            $read = $this->clients;
            $read[] = $this->socket;
            socket_select($read, $write, $except, null);
            // 新连接
            if (in_array($this->socket, $read)) {
                $newClient = socket_accept($this->socket);
                $this->handshake($newClient);
                $this->clients[] = $newClient;
            }
            // 处理客户端消息
            foreach ($read as $client) {
                if ($client === $this->socket) continue;
                $data = @socket_read($client, 1024);
                if ($data) {
                    $data = $this->decode($data);
                    echo "收到: $data\n";
                    // 广播给所有客户端
                    foreach ($this->clients as $c) {
                        if ($c !== $client) {
                            socket_write($c, $this->encode($data));
                        }
                    }
                } else {
                    // 客户端断开
                    $index = array_search($client, $this->clients);
                    unset($this->clients[$index]);
                    socket_close($client);
                }
            }
        }
    }
    // WebSocket 握手
    private function handshake($client) {
        $request = socket_read($client, 1024);
        preg_match('/Sec-WebSocket-Key:\s(.*)\r\n/', $request, $matches);
        $key = $matches[1] ?? '';
        $accept = base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
        $response = "HTTP/1.1 101 Switching Protocols\r\n"
                   . "Upgrade: websocket\r\n"
                   . "Connection: Upgrade\r\n"
                   . "Sec-WebSocket-Accept: $accept\r\n\r\n";
        socket_write($client, $response);
    }
    // 解码客户端消息
    private function decode($payload) {
        $length = ord($payload[1]) & 127;
        $mask = substr($payload, 2, 4);
        $data = substr($payload, 6);
        $decoded = '';
        for ($i = 0; $i < strlen($data); $i++) {
            $decoded .= $data[$i] ^ $mask[$i % 4];
        }
        return $decoded;
    }
    // 编码发送给客户端的消息
    private function encode($data) {
        $payload = '81';
        $len = strlen($data);
        if ($len <= 125) {
            $payload .= sprintf('%02X', $len);
        } elseif ($len <= 65535) {
            $payload .= '7E' . sprintf('%04X', $len);
        } else {
            $payload .= '7F' . sprintf('%08X', $len);
        }
        $payload .= bin2hex($data);
        return hex2bin($payload);
    }
}
// 使用
$server = new WebSocketServer('0.0.0.0', 8080);
$server->run();

客户端示例(JavaScript)

// 连接 WebSocket
const ws = new WebSocket('ws://localhost:2346');
// 连接建立时
ws.onopen = function() {
    console.log('连接成功');
    ws.send('Hello Server!');
};
// 接收消息
ws.onmessage = function(event) {
    console.log('收到服务器消息:', event.data);
};
// 关闭连接
ws.onclose = function() {
    console.log('连接关闭');
};
// 错误处理
ws.onerror = function(error) {
    console.error('错误:', error);
};

推荐方案对比

方案 优点 缺点 适用场景
Workerman 性能好、功能全、文档丰富 需要 PHP CLI 环境 生产环境、高性能需求
Ratchet 简单易用、纯 PHP 性能一般 中小型项目
原生实现 无依赖 复杂、容易出错 学习研究

部署注意事项

  1. 使用 PHP CLI 模式:WebSocket 服务需要长驻内存,不能使用 PHP-FPM
  2. 防火墙配置:确保 WebSocket 端口对外开放
  3. 反向代理:可以使用 Nginx 反向代理 WebSocket
  4. SSL 支持:生产环境建议使用 WSS(WebSocket Secure)

如果需要更多帮助,请告诉我你的具体使用场景!

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