PHP Magazin

PHP, JavaScript, Open Web Technologies

WebSocket-Implementierung mit PHP

X

Alles zu Facebook Hack findet Ihr in unserer neuen Serie: What the Hack?!

Push it mit HTML5!

WebSocket-Implementierung mit PHP

Daniel Schmitzer

Die WebSocket-Technik ist ein Teil der HTML-5-Spezifikation und dient zur bidirektionalen Kommunikation zwischen Server und Browser. Es soll gezeigt werden, wie WebSockets funktionieren und welche Unterschiede zu bisherigen Comet-Lösungen bestehen. Die Funktionsweise auf Serverseite werden wir beispielhaft am Aufbau einer Socket-Verbindung und einer kleinen Chatapplikation erläutern. Weiterhin werden die Anforderungen auf Clientseite aufgezeigt und ein Ausblick auf mögliche Anwendungen gegeben.

Bisher war die Kommunikation im Internet klar geregelt. Der Server durfte nur "sprechen", wenn er auch gefragt wurde. Dieses Verfahren wird als Pull-Technologie bezeichnet, da sich der Client alle Informationen vom Server ziehen muss. Im Web 2.0 wurde es aber immer öfter notwendig, dass bestimmte Informationen unmittelbar vom Server an die Clients weitergeleitet werden mussten (Push-Technologie, da die Informationen vom Server zum Clienten geschoben werden). Beispiele für solche Anwendungen sind Chat- und Nachrichtensysteme oder aber auch Browserspiele mit Mehrspielermodus. Bisher wurde die Push-Technologie durch verschiedene Verfahren simuliert. Eine Möglichkeit ist es, ein IFrame in die Seite einzubinden und eine Anfrage an den Server zu senden, die erst beantwortet wird, wenn der Server eine Nachricht an den Clienten senden will. Diese Technik hat aber viele Nachteile, z. B. können Proxys oder Firewalls diese Art von langen Anfragen unterbinden, weiterhin wird eine weitere Verbindung zum Server benötigt, die diesen unnötig belastet.

Eine weitere Möglichkeit ist die Nutzung des XMLHttpRequests, die durch eine Multipart-Nachricht des Servers eine Stream-Verbindung von Server zu Client ermöglicht. Das XMLHttpRequest-Objekt ist auch vom W3C spezifiziert worden und stellt eine Alternative zu den neuen WebSockets dar. Der Nachteil des XMLHttpRequest-Objekts ist, dass es in den verschiedenen Browsern unterschiedlich implementiert wurde. Eine weitere Möglichkeit die Push-Technologie zu simulieren ist das ständige Nachfragen des Clients, ob der Server eine neue Nachricht für den Clienten hat. Diese Techniken werden oft auch als "Comet"-Lösungen bezeichnet. Im TCP-/IP-Bereich oder auch in der Interprozesskommunikation gibt es aber längst bessere und standardisierte Techniken. Es haben sich hier Socket-Verbindungen zwischen Server und Client durchgesetzt. Vorteile und Eigenschaften von Socket-Verbindungen:

  • persistent (sie bleiben nach jeder Nachricht weiterhin bestehen, bis sie geschlossen werden)
  • bidirektional (das Senden ist in beide Richtungen jederzeit möglich)
  • performant (kein großer Protokoll-Overhead, wie bei Request-/Response-Techniken)

Mit HTML 5 gibt es nun auch eine Spezifikation für WebSockets, die eine bidirektionale Socket-Verbindung zwischen Client und Server ermöglicht, in der Nachrichten in beide Richtungen gesendet werden können. Vom W3C wurde das allgemeine Clientinterface spezifiziert, die erste Version stammt bereits vom 23. April 2009 und liegt aktuell in einer Version vom 1. Juni 2010 vor. Es gibt auch eine Erweiterung der WHATWG-Gruppe mit einigen Erweiterungen, die über die Spezifikation des W3C hinausgehen.

Funktionsweise von Socket-Verbindungen

Ein Socket ist ein Kommunikationsendpunkt. Es werden dabei die Techniken und Funktionen der untersten vier Ebenen des OSI- (Open System Interconnection Reference) Models gekapselt. Um eine Socket-Verbindung herzustellen, benötigt man einen Server, der auf einer Adresse und einem Port "lauscht" und auf eingehende Verbindungen wartet. Dieser Vorgang wird als "binden" (bind) bezeichnet, da man den Socket an die Adresse und den Port bindet, an der er Anfragen akzeptiert. Das warten auf eingehende Verbindungen wird als "lauschen" (listen) bezeichnet. Versucht sich nun ein Client mit dem Server zu verbinden, so wird aus dem "lauschenden" Socket ein neuer Socket abgeleitet, der für die Verbindung zwischen diesem speziellen Clienten und dem Server zuständig ist. Der "lauschende" Socket bleibt dabei erhalten und wartet auf weitere Clientverbindungen. Der Server muss nun die Clientverbindungen verwalten und kann über diese Nachrichten an bestimmte oder alle Clients senden. Socket-Verbindungen bleiben erhalten, auch nachdem eine Nachricht gesendet wurde und erlauben über die ClientSockets Nachrichtenaustausch in beide Richtungen.

Server für Socket-Verbindungen mit PHP

Da WebSocket-Verbindungen nichts anderes sind als normale Socket-Verbindungen, können die in PHP ab Version 4.1.0 enthaltenen Funktionen genutzt werden, um einen Server für WebSocket-Verbindungen zu erstellen. Um die PHP-internen Socket-Funktionen nutzen zu können, muss ihr PHP mit der Socket-Unterstützung kompiliert sein. Dies erreichen sie unter UNIX mit der --enable-sockets-Option während der Konfiguration. Unter Windows müssen sie lediglich die entsprechende Bibliothek php_sockets.dll in der php.ini laden.

Um nun eine Socket-Verbindung aufzubauen, muss als Erstes der Socket erstellt werden. Dies geschieht in PHP mit der Funktion socket_create. Sie benötigt drei Parameter: die Protokollfamilie, den Typ und das Protokoll. Da die WebSockets auf dem TCP/IP(-Protokoll) basieren, wählen wir SOL_TCP als Protokoll und AF_INET als Protokollfamilie. Der SocketType sollte auf SOCK_STREAM gestellt werden.

Dem Socket muss natürlich eine Adresse und eine Portnummer zugewiesen werden, an die er gebunden werden soll. Dies geschieht mit der Funktion socket_bind. Nun muss man den Socket noch dazu bringen, auf eingehende Verbindungen zu warten, dies geschieht durch die Funktion socket_listen. Wurden diese Funktionen erfolgreich aufgerufen, kann mittels socket_select das Array mit den Sockets (am Anfang nur der ServerSocket) auf Statusänderungen überwacht werden. Dies geschieht durch die Funktion socket_select. Wird eine Anfrage an den ServerSocket gestellt, so wird mittels socket_accept ein neuer ClientSocket erstellt. Lesender Zugriff ist auf den ClientSockets mittels socket_recv möglich, schreibender Zugriff ist dagegen über die Funktion socket_write möglich. Listing 1 zeigt einen einfachen Server, der auf eingehende Socket-Verbindungen wartet.

// Error Reporting und Zeitlimit für Serverbetrieb setzen
error_reporting(E_ERROR);
set_time_limit (0);

$host = 'localhost'; // Serverhost auf der gelauscht werden soll
$port = 1414; // Port auf dem Verbindungen angenommen werden sollen

// Socket erstellen
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

// Socket an Adresse und Port binden
socket_bind($sock, $host, $port);

// An Port lauschen
socket_listen($sock);

$sockets = array($sock);
$arClients = array();

while (true)
{

echo "Warte auf Verbindung...\r\n";

$sockets_change = $sockets;
$ready = socket_select($sockets_change, $write = null, $expect = null, null);

echo "Verbindung angenommen.\r\n";

foreach($sockets_change as $s)
{
if ($s == $sock)
{
// Änderung am Serversocket
$client = socket_accept($sock);
array_push($sockets, $client);
print_r($sockets);
}
else
{
// Eingehende Nachrichten der Clientsockets
$bytes = @socket_recv($s, $buffer, 2048, 0);
}
}
}
 
Verwandte Themen: 

Kommentare

Seiten

Ihr Kommentar zum Thema

Als Gast kommentieren:

Gastkommentare werden nach redaktioneller Prüfung freigegeben (bitte Policy beachten).