WebSockets – Sockets im Web

Da bald die Abgabe meiner Abschlussarbeit ansteht und mein Thema sich rund um Websockets dreht, wird es Zeit eine Einführung in das relativ neue Themengebiet zu schreiben. Das WebSocket-Protokoll ist ein auf TCP basierendes Netzwerkprotokoll, das entworfen wurde, um eine bidirektionale Verbindung zwischen einer Webanwendung und einem WebSocket-Server bzw. einem Web-Server, der WebSockets unterstützt, herzustellen.

WebSocket Events

Das Problem: Client-Server und Server-Client Verbindungen mit geringer Latenz

Das HTTP-Protokoll basiert mehr oder weniger auf dem Anfrage/Antwort Prinzip. Der Client lädt eine Seite und es passiert weiter nichts, bis er auf einen weiteren Link klickt. Gegen 2005 sorgte dann AJAX dafür, dass das Internet dynamischer wirkte. Dennoch wurde die gesamte HTTP-Kommunikation vom Client gesteuert.  Dieser benötigt zum Ldaen neuer Daten vom Server die Interaktion der Nutzer oder periodische Abfragen.

Beim WebSocket-Protokoll werden keine Aktionen der Nutzer benötigt, hier reicht es im Client eine Verbindung zu öffnen. Diese geöffnete Verbindung kann dann aktiv vom Server verwendet werden. Der Server muss also nicht mehr Anfragen vom Client abwarten, sondern kann neue Informationen ausliefern, ohne auf eine neue Verbindung des Clients zu warten.

Ein Server-Push ist bei einer reinen HTTP-Verbindung nur durch verzögerte Antworten und Polling des Clients möglich. Zudem entfällt bei WebSockets der HTTP-Overhead, der bei jeder Anfrage einige Hundert Byte umfassen kann.

Wenn man nun beispielsweise an aufwendige Shooter-Spiele mit mehreren Mitspielern im Browser denkt, wird einem schnell klar das hier das HTTP-Protokoll fehl am Platz ist, da hier keine geringe Latenz geschaffen werden kann.

Der Anfang mit den WebSockets

Um eine Verbindung herzustellen, reicht es aus, den WebSocket Konstruktor aufzurufen:

// normal, "unsecure" connection
var socket = new WebSocket('ws://localhost/echo');

// encrypted, "secure" connection
var socket = new WebSocket('wss://localhost/echo');

Die WebSocket-Protokoll-Spezifikation definiert zwei neue URI-Schemenws: für unverschlüsselte, und wss: für verschlüsselte Verbindungen. Der WebSocket Konstruktor erlaubt auch die Angabe eines zweiten Arguments: optionale Subprotokolle. Dies kann ein String sein oder ein Array, bestehend aus Strings. Der WebSocket-Server muss dann entscheiden welches Subprotokoll verwendet werden soll. Die Subprotokoll Namen müssen eines der von IANA Registrierung festgelegten sein. Aktuell sind das SOAP oder WAMP.

Wenn Event-Listener an die Verbindung angehängt werden, kann sofort gesehen werden ob die Verbindung besteht, ein Fehler aufgetreten ist oder Mitteilungen eingetroffen sind.

// When the connection is open, send some data to the server
socket.onopen = function () {
    socket.send('Ping'); // Send the message 'Ping' to the server
};

// Log errors
socket.onerror = function (error) {
    console.log('WebSocket Error ' + error);
};

// Log messages from the server
socket.onmessage = function (e) {
    console.log('Server: ' + e.data);
};

Mit dem Server Kommunizieren

Sobald eine Verbindung zum Server besteht (open-Event), können wir Daten mittels send('die Nachricht') über das socket-Objekt zum Server schicken. Dieses kann Strings sowie Binary-Messages verarbeiten. Um binary data zum Server zu schicken muss dies entweder ein ArrayBuffer oder ein blob-Objekt sein.

// Sending String
socket.send('your message');

// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
    binary[i] = img.data[i];
}
socket.send(binary.buffer);

// Sending file as Blob
var file = document.querySelector('input[type="file"]').files[0];
socket.send(file);

Natürlich schickt uns auch der Server Nachrichten zu jeder Zeit. Wann immer dies passiert, wird der onmessage-Callback gefeuert. Der Callback bekommt ein event-Objekt und die eigentliche Nachricht ist über das data Attribut erreichbar.

Status der Implementierung

Um mit WebSockets arbeiten zu können, bedarf es noch einen Browser der die Spezifikation implementiert hat. Ich gehe hier auf die letzte Spezifikation (RFC 6455) ein.

Internet Explorer Firefox Google Chrome Safari Opera
ab IE 10 PP5 ab FF 11 ab Chrome 16 ab Safari 6 ab Opera 10.5

In Opera sind WebSockets aber per Standard deaktiviert. Mozilla Firefox implementierte WebSockets bereits ab Version 6, allerdings als MozWebSocket genannt.

Serverseitig

Aufgrund von WebSockets entstehen neue Interaktionsmöglichkeiten für serverseitige Anwendungen. Herkömmliche Server, wie LAMP, kommen oftmals mit einer großen Anzahl offener WebSocket-Verbindung nicht zurecht. Hierbei wird eine andere Architektur notwendig, die gleichzeitig eine hohe Anzahl an WebSocket-Verbindungen zulässt und keine Leistungseinbußen hat. Solche Architekturen werden meistens um Threading oder nicht-blockierende IOs konzipiert.

Serverseitige Implementierungen:

Demos