Что такое WebSocket и зачем он нужен в PHP
Традиционный HTTP-протокол работает по схеме «запрос-ответ»: клиент отправляет запрос, сервер обрабатывает его и возвращает ответ. Для получения новых данных клиенту приходится постоянно перезагружать страницу или использовать AJAX-polling (периодические запросы к серверу). Такой подход создает избыточную нагрузку и не обеспечивает настоящей «живой» связи.
WebSocket (RFC 6455) — это протокол, который устанавливает постоянное двунаправленное соединение между клиентом (браузером) и сервером. После рукопожатия (handshake) данные могут передаваться в обе стороны в реальном времени без повторных HTTP-запросов. Это идеальное решение для:
- Чатов и мессенджеров
- Лент новостей и уведомлений
- Совместного редактирования документов
- Игр и аукционов
- Мониторинга и дашбордов
Многие считают, что PHP не подходит для real-time задач из-за своей синхронной природы. Однако с появлением библиотек вроде Ratchet и ReactPHP ситуация кардинально изменилась. PHP может эффективно работать с WebSocket, используя событийно-ориентированную архитектуру и неблокирующий ввод-вывод.
Архитектура WebSocket-приложения на PHP
Прежде чем писать код, важно понять, как устроено WebSocket-соединение на стороне сервера PHP.
Этапы установки соединения
- HTTP-рукопожатие (handshake): Клиент отправляет специальный HTTP-запрос с заголовком
Upgrade: websocket. Сервер проверяет ключSec-WebSocket-Keyи возвращает ответ со статусом 101 Switching Protocols. - Переключение протокола: После успешного рукопожатия соединение переводится в режим WebSocket. Дальнейший обмен данными идет по бинарным фреймам.
- Дуплексная связь: Сервер и клиент могут отправлять сообщения в любой момент, пока соединение не будет закрыто одной из сторон.
Синхронный 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