Moderne Webanwendungen benötigen häufig eine Echtzeitkommunikation zwischen Server und Browser. Klassisches HTTP arbeitet nach dem Request-Response-Prinzip, bei dem der Client jede Anfrage selbst initiieren muss. WebSockets lösen dieses Problem durch eine persistente, bidirektionale Verbindung über TCP. Dieses Tutorial erklärt das WebSocket-Protokoll, zeigt den Verbindungsaufbau per Handshake und führt Schritt für Schritt durch die Einrichtung eines WebSocket-Servers in PHP mit der Bibliothek Ratchet.

Bevor es an die Implementierung geht, lohnt sich ein Blick auf das Protokoll selbst und seine Unterschiede zu klassischem HTTP.
Was sind WebSockets?
WebSockets sind ein Kommunikationsprotokoll, das eine dauerhafte Verbindung zwischen Client und Server ermöglicht. Im Gegensatz zu HTTP bleibt die Verbindung nach dem initialen Handshake geöffnet. Beide Seiten können jederzeit Nachrichten senden, ohne dass eine neue Anfrage gestartet werden muss. Das Protokoll basiert auf TCP und eignet sich besonders für Anwendungen wie Chat-Systeme, Live-Dashboards oder Multiplayer-Spiele.
sequenceDiagram
participant Browser
participant Server
Browser->>Server: HTTP Upgrade Request
Server->>Browser: 101 Switching Protocols
Browser->>Server: Nachricht senden
Server->>Browser: Nachricht weiterleiten
Browser->>Server: Verbindung schließen
Das Diagramm zeigt den typischen Ablauf einer WebSocket-Verbindung. Der Browser sendet zunächst einen HTTP-Upgrade-Request, woraufhin der Server mit dem Statuscode 101 Switching Protocols antwortet. Danach ist die Verbindung offen und beide Seiten können frei Nachrichten austauschen.
Wie funktioniert der WebSocket-Handshake?
Der Verbindungsaufbau beginnt mit einem gewöhnlichen HTTP-Request, der spezielle Header enthält. Der Client signalisiert dem Server, dass er auf das WebSocket-Protokoll wechseln möchte.
<?php
/* Beispiel: HTTP-Upgrade-Header eines WebSocket-Handshakes */
$upgradeHeaders = [
'Host' => 'localhost:8080',
'Upgrade' => 'websocket',
'Connection' => 'Upgrade',
'Sec-WebSocket-Key' => base64_encode(random_bytes(16)),
'Sec-WebSocket-Version' => '13'
];
foreach ($upgradeHeaders as $key => $value) {
echo $key . ': ' . $value . PHP_EOL;
}
Der Header Upgrade: websocket teilt dem Server mit, dass ein Protokollwechsel gewünscht ist. Der Sec-WebSocket-Key ist ein zufällig generierter Base64-Wert, den der Server zur Bestätigung nutzt. Nach erfolgreicher Validierung antwortet der Server mit 101 Switching Protocols und die TCP-Verbindung bleibt bestehen. Ab diesem Zeitpunkt läuft die gesamte Kommunikation über das WebSocket-Protokoll statt über HTTP.
WebSocket-Server mit Ratchet aufsetzen
Ratchet ist die verbreitetste PHP-Bibliothek für WebSocket-Server. Sie abstrahiert die Details des Handshakes und der Frame-Verarbeitung, sodass Entwickler sich auf die Anwendungslogik konzentrieren können. Die Installation erfolgt über Composer.
<?php
/* Installation per Composer (im Terminal ausführen):
composer require cboden/ratchet
*/
/* Abhängigkeiten prüfen */
$required = [
'cboden/ratchet' => 'WebSocket-Server',
'react/event-loop' => 'Event Loop',
'react/socket' => 'Socket-Handling'
];
foreach ($required as $paket => $beschreibung) {
echo $paket . ' => ' . $beschreibung . PHP_EOL;
}
Nach der Installation steht das komplette Ratchet-Framework zur Verfügung. Es bringt automatisch die React-PHP-Bibliotheken mit, die für den Event Loop und das Socket-Handling notwendig sind. Wichtig zu wissen ist, dass der WebSocket-Server als eigenständiger PHP-CLI-Prozess läuft und nicht innerhalb von Apache oder Nginx ausgeführt wird.
Nachrichten senden und empfangen
Die zentrale Komponente eines Ratchet-Servers ist eine Klasse, die das Interface MessageComponentInterface implementiert. Dieses Interface definiert vier Methoden: onOpen, onMessage, onClose und onError.
<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class ChatServer implements MessageComponentInterface
{
protected \SplObjectStorage $clients;
public function __construct()
{
$this->clients = new \SplObjectStorage();
}
public function onOpen(ConnectionInterface $conn): void
{
$this->clients->attach($conn);
echo "Neue Verbindung: {$conn->resourceId}" . PHP_EOL;
}
public function onMessage(
ConnectionInterface $from,
$msg
): void {
/* Nachricht an alle anderen Clients weiterleiten */
foreach ($this->clients as $client) {
if ($from !== $client) {
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn): void
{
$this->clients->detach($conn);
echo "Verbindung getrennt: {$conn->resourceId}" . PHP_EOL;
}
public function onError(
ConnectionInterface $conn,
\Exception $e
): void {
echo "Fehler: {$e->getMessage()}" . PHP_EOL;
$conn->close();
}
}
Die Klasse nutzt SplObjectStorage, um alle aktiven Verbindungen zu speichern. Bei onOpen wird eine neue Verbindung registriert. Die Methode onMessage leitet eingehende Nachrichten an alle anderen verbundenen Clients weiter. Bei onClose wird die Verbindung aus dem Speicher entfernt. onError schließt die fehlerhafte Verbindung. Dieses Muster bildet die Grundlage für Broadcast-Szenarien wie Chat-Anwendungen.
Um den Server zu starten, wird ein Startskript benötigt, das die Ratchet-Komponenten zusammenfügt.
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
$server = IoServer::factory(
new HttpServer(
new WsServer(
new ChatServer()
)
),
8080
);
echo "WebSocket-Server läuft auf Port 8080" . PHP_EOL;
$server->run();
Der Server wird mit php server.php im Terminal gestartet und wartet dann auf eingehende Verbindungen auf Port 8080. Die Schachtelung aus IoServer, HttpServer und WsServer sorgt dafür, dass der HTTP-Handshake korrekt verarbeitet und anschließend auf das WebSocket-Protokoll gewechselt wird.
JavaScript-Client im Browser
Der Browser stellt die Verbindung zum WebSocket-Server über die native WebSocket-API her. Kein zusätzliches Framework ist dafür notwendig.
<?php
/* Folgendes JavaScript wird im Browser ausgeführt */
$jsClient = <<<'JS'
const ws = new WebSocket('ws://localhost:8080');
ws.onopen = function() {
console.log('Verbindung hergestellt');
ws.send('Hallo vom Browser!');
};
ws.onmessage = function(event) {
console.log('Nachricht erhalten:', event.data);
};
ws.onclose = function() {
console.log('Verbindung geschlossen');
};
JS;
echo $jsClient;
Das onopen-Event signalisiert, dass die Verbindung erfolgreich aufgebaut wurde. Mit ws.send() werden Nachrichten an den Server gesendet. Das onmessage-Event empfängt Nachrichten, die der Server weiterleitet. Durch onclose kann die Anwendung auf das Schließen der Verbindung reagieren, etwa um einen Reconnect-Versuch zu starten.
Einsatzgebiete und Grenzen
WebSockets eignen sich hervorragend für Szenarien, in denen Daten in Echtzeit ausgetauscht werden müssen. Chat-Anwendungen, Live-Benachrichtigungen, kollaborative Editoren und Echtzeit-Dashboards profitieren stark von der persistenten Verbindung. Allerdings gibt es auch Einschränkungen. Auf Shared Hosting sind WebSockets oft nicht verfügbar, da ein dauerhaft laufender PHP-CLI-Prozess erforderlich ist. Firewalls und Reverse-Proxys können WebSocket-Verbindungen blockieren. Für den produktiven Einsatz empfiehlt sich ein Prozessmanager wie Supervisor oder systemd, der den Server automatisch neu startet. Wenn nur der Server Daten an den Client senden soll, ist Server-Sent Events (SSE) eine einfachere Alternative. Für seltene Aktualisierungen reicht auch Long Polling über klassisches HTTP.
Fazit
WebSockets ermöglichen eine bidirektionale Echtzeitkommunikation zwischen PHP-Server und Browser. Der Verbindungsaufbau erfolgt über einen HTTP-Upgrade-Handshake, nach dem die TCP-Verbindung dauerhaft offen bleibt. Mit der Bibliothek Ratchet lässt sich ein WebSocket-Server in PHP schnell aufsetzen. Die Server-Klasse implementiert das MessageComponentInterface mit den Methoden onOpen, onMessage, onClose und onError. Im Browser reicht die native WebSocket-API für die Verbindung aus. Wichtig ist, dass der Server als PHP-CLI-Prozess läuft und nicht über den Webserver gestartet wird. Für Produktionsumgebungen sollte ein Prozessmanager den Server dauerhaft am Laufen halten.