WebSocket на PHP: real-time приложения от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое WebSocket и зачем он нужен в PHP

Традиционный HTTP-протокол работает по схеме «запрос-ответ»: клиент отправляет запрос, сервер обрабатывает его и возвращает ответ. Для получения новых данных клиенту приходится постоянно перезагружать страницу или использовать AJAX-polling (периодические запросы к серверу). Такой подход создает избыточную нагрузку и не обеспечивает настоящей «живой» связи.

WebSocket (RFC 6455) — это протокол, который устанавливает постоянное двунаправленное соединение между клиентом (браузером) и сервером. После рукопожатия (handshake) данные могут передаваться в обе стороны в реальном времени без повторных HTTP-запросов. Это идеальное решение для:

  • Чатов и мессенджеров
  • Лент новостей и уведомлений
  • Совместного редактирования документов
  • Игр и аукционов
  • Мониторинга и дашбордов

Многие считают, что PHP не подходит для real-time задач из-за своей синхронной природы. Однако с появлением библиотек вроде Ratchet и ReactPHP ситуация кардинально изменилась. PHP может эффективно работать с WebSocket, используя событийно-ориентированную архитектуру и неблокирующий ввод-вывод.

Архитектура WebSocket-приложения на PHP

Прежде чем писать код, важно понять, как устроено WebSocket-соединение на стороне сервера PHP.

Этапы установки соединения

  1. HTTP-рукопожатие (handshake): Клиент отправляет специальный HTTP-запрос с заголовком Upgrade: websocket. Сервер проверяет ключ Sec-WebSocket-Key и возвращает ответ со статусом 101 Switching Protocols.
  2. Переключение протокола: После успешного рукопожатия соединение переводится в режим WebSocket. Дальнейший обмен данными идет по бинарным фреймам.
  3. Дуплексная связь: Сервер и клиент могут отправлять сообщения в любой момент, пока соединение не будет закрыто одной из сторон.

Синхронный PHP vs Асинхронный PHP

Обычный PHP-скрипт работает синхронно: один запрос — один процесс, после ответа скрипт завершается. Для WebSocket требуется постоянно работающий процесс, который слушает порт и обрабатывает множество одновременных соединений. Именно здесь на помощь приходит ReactPHP — библиотека, реализующая событийный цикл (event loop) для PHP.

Библиотека Ratchet построена поверх ReactPHP и предоставляет удобный интерфейс для создания WebSocket-серверов. Она берет на себя низкоуровневую работу с сокетами, парсинг фреймов и управление соединениями.

Практическая реализация: создаем real-time чат

Рассмотрим создание простого чата на WebSocket с помощью Ratchet. Этот пример можно адаптировать под любые real-time задачи.

Шаг 1: Установка зависимостей

Убедитесь, что у вас установлен Composer (менеджер зависимостей для PHP). Установите Ratchet и его зависимости:

composer require cboden/ratchet

Шаг 2: Создание класса-обработчика

Создадим файл ChatServer.php, который будет управлять соединениями и сообщениями:

<?php
namespace MyApp;

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class ChatServer implements MessageComponentInterface
{
    protected $clients;

    public function __construct()
    {
        // SplObjectStorage — удобный способ хранить объекты соединений
        $this->clients = new \SplObjectStorage;
        echo "Сервер запущен!\n";
    }

    public function onOpen(ConnectionInterface $conn)
    {
        // Новый клиент подключился
        $this->clients->attach($conn);
        echo "Новое подключение: {$conn->resourceId}\n";
    }

    public function onMessage(ConnectionInterface $from, $msg)
    {
        // Получено сообщение от одного из клиентов
        $numRecv = count($this->clients) - 1;
        echo "Сообщение от {$from->resourceId}: {$msg}\n";

        // Отправляем сообщение всем остальным клиентам
        foreach ($this->clients as $client) {
            if ($from !== $client) {
                $client->send($msg);
            }
        }
    }

    public function onClose(ConnectionInterface $conn)
    {
        // Клиент отключился
        $this->clients->detach($conn);
        echo "Подключение {$conn->resourceId} закрыто\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e)
    {
        echo "Ошибка: {$e->getMessage()}\n";
        $conn->close();
    }
}

Шаг 3: Запуск сервера

Создадим скрипт server.php, который запускает WebSocket-сервер на порту 8080:

<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\ChatServer;

require __DIR__ . '/vendor/autoload.php';

$server = IoServer::factory(
    new HttpServer(
        new WsServer(
            new ChatServer()
        )
    ),
    8080
);

echo "WebSocket сервер слушает порт 8080...\n";
$server->run();

Запустите сервер из командной строки:

php server.php

Сервер будет работать, пока вы не остановите его (Ctrl+C).

Шаг 4: Клиентская часть (JavaScript)

Создайте HTML-страницу с простым интерфейсом чата:

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket Чат</title>
    <meta charset="utf-8">
</head>
<body>
    <h2>Чат на WebSocket</h2>
    <div id="messages" style="border:1px solid #ccc; height:300px; overflow-y:scroll; padding:10px;"></div>
    <input type="text" id="msgInput" placeholder="Введите сообщение..." style="width:300px;">
    <button onclick="sendMessage                

Блоги

Рекомендаций по книгам