Einführung in WebSockets – Sockets im Web

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

Das Web basiert größtenteils auf dem sogenannten Anfrage-/Antwort-Paradigma von HTTP. Ein Client lädt eine Webseite hoch und dann passiert nichts, bis der Nutzer auf die nächste Seite klickt. Ungefähr im Jahr 2005 sorgte AJAX dafür, dass das Web dynamischer wirkte. Dennoch wurde die gesamte HTTP-Kommunikation vom Client gesteuert, was Nutzerinteraktionen oder regelmäßige Abfragen zum Laden neuer Daten vom Server erforderte.

Schon seit einiger Zeit gibt es Technologien, mit denen der Server Daten in dem Moment an den Client senden kann, wenn er weiß, dass neue Daten verfügbar sind. Sie heißen beispielsweise „Push“ oder „Comet“. Einer der häufigsten Hacks, um den Anschein einer vom Server initiierten Verbindung zu erzeugen, wird als Long Polling bezeichnet. Bei langen Abfragen öffnet der Client eine HTTP-Verbindung zum Server, die ihn offen lässt, bis eine Antwort gesendet wird. Immer wenn der Server neue Daten hat, sendet er eine Antwort. Bei anderen Methoden handelt es sich um Flash-Anfragen, mehrteilige XHR-Anfragen und sogenannte HTML-Dateien. Lange Abfragen und die anderen Methoden funktionieren ziemlich gut. Sie werden täglich in Anwendungen wie dem Gmail-Chat verwendet.

All diese Behelfslösungen haben jedoch ein Problem: Sie nutzen den Mehraufwand von HTTP, was sie nicht besonders für Anwendungen mit niedriger Latenz geeignet macht. Denken Sie an Multiplayer-Ego-Shooter im Browser oder andere Online-Spiele mit Echtzeit-Komponente.

Einführung zu WebSocket: Sockets im Web

Die WebSocket-Spezifikation definiert eine API, die Socket-Verbindungen zwischen einem Webbrowser und einem Server herstellt. Kurz gesagt: Es besteht eine dauerhafte Verbindung zwischen dem Client und dem Server und beide Parteien können jederzeit mit dem Senden von Daten beginnen.

Erste Schritte

Sie öffnen eine WebSocket-Verbindung ganz einfach durch Aufrufen des WebSocket-Konstruktors:

var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);

Beachten Sie die ws:. Dies ist das neue URL-Schema für WebSocket-Verbindungen. Außerdem gibt es wss: für sichere WebSocket-Verbindungen, genauso wie https: für sichere HTTP-Verbindungen.

Wenn Sie einige Event-Handler sofort an die Verbindung anhängen, können Sie erkennen, wann die Verbindung geöffnet ist, eingehende Nachrichten empfangen wurden oder ob ein Fehler aufgetreten ist.

Das zweite Argument akzeptiert optionale Subprotokolle. Es kann ein String oder ein Array von Strings sein. Jeder String sollte einen Subprotokollnamen darstellen und der Server akzeptiert nur eines der übergebenen Subprotokolle im Array. Das akzeptierte Subprotokoll wird durch den Zugriff auf das Attribut protocol des WebSocket-Objekts ermittelt.

Die Subprotokollnamen müssen einer der registrierten Subprotokollnamen in der IANA Registry sein. Derzeit gibt es nur einen seit Februar 2012 registrierten Subprotokollnamen (Soap).

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

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

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

Kommunikation mit dem Server

Sobald eine Verbindung zum Server besteht (wenn das open-Ereignis ausgelöst wurde), können wir mit der send('your message')-Methode für das Verbindungsobjekt Daten an den Server senden. Bisher wurden nur Strings unterstützt, aber in der neuesten Spezifikation können jetzt auch Binärnachrichten gesendet werden. Zum Senden von Binärdaten können Sie entweder das Blob- oder das ArrayBuffer-Objekt verwenden.

// Sending String
connection.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];
}
connection.send(binary.buffer);

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

Ebenso kann der Server uns jederzeit Nachrichten senden. Wenn dies geschieht, wird der onmessage-Callback ausgelöst. Der Callback empfängt ein Ereignisobjekt und die eigentliche Nachricht kann über die data-Eigenschaft aufgerufen werden.

WebSocket kann auch Binärnachrichten gemäß der neuesten Spezifikation empfangen. Binärframes können im Blob- oder ArrayBuffer-Format empfangen werden. Um das Format der empfangenen Binärdatei anzugeben, setzen Sie die Eigenschaft "binaryType" des WebSocket-Objekts auf "blob" oder "arraybuffer". Das Standardformat ist „blob“. Sie müssen den binaryType-Parameter beim Senden nicht abstimmen.

// Setting binaryType to accept received binary as either 'blob' or 'arraybuffer'
connection.binaryType = 'arraybuffer';
connection.onmessage = function(e) {
console.log(e.data.byteLength); // ArrayBuffer object if binary
};

Eine weitere neu hinzugefügte Funktion von WebSocket sind Erweiterungen. Wenn Sie Erweiterungen verwenden, können Sie Frames komprimiert, geteilt usw. senden. Vom Server akzeptierte Erweiterungen finden Sie, indem Sie die Erweiterungseigenschaft des WebSocket-Objekts nach dem Open-Ereignis untersuchen. Im Februar 2012 gibt es noch keine offiziell veröffentlichten Erweiterungsspezifikationen.

// Determining accepted extensions
console.log(connection.extensions);

Ursprungsübergreifende Kommunikation

Als modernes Protokoll ist die ursprungsübergreifende Kommunikation direkt in WebSocket integriert. Sie sollten dennoch sicherstellen, dass Sie nur mit vertrauenswürdigen Clients und Servern kommunizieren, WebSocket ermöglicht die Kommunikation zwischen Parteien in jeder Domain. Der Server entscheidet, ob sein Dienst für alle Clients verfügbar ist oder nur für diejenigen, die sich in einer Reihe klar definierter Domains befinden.

Proxyserver

Jede neue Technologie bringt neue Probleme mit sich. Im Fall von WebSocket ist es die Kompatibilität mit Proxyservern, die HTTP-Verbindungen in den meisten Unternehmensnetzwerken vermitteln. Das WebSocket-Protokoll verwendet das HTTP-Upgradesystem (das normalerweise für HTTP/SSL verwendet wird), um eine HTTP-Verbindung auf eine WebSocket-Verbindung „Upgrade“ durchzuführen. Einige Proxyserver tun dies nicht und unterbrechen die Verbindung. Daher ist es eventuell nicht möglich, eine Verbindung herzustellen, selbst wenn ein bestimmter Client das WebSocket-Protokoll verwendet. Deshalb ist der nächste Abschnitt noch wichtiger :)

WebSockets heute verwenden

WebSocket ist noch eine junge Technologie und noch nicht in allen Browsern implementiert. Sie können WebSocket jedoch aktuell mit Bibliotheken verwenden, die eine der oben genannten Alternativen verwenden, wenn WebSocket nicht verfügbar ist. Eine in dieser Domain sehr beliebte Bibliothek ist socket.io. Sie verfügt über eine Client- und eine Serverimplementierung des Protokolls sowie Fallbacks. Socket.io unterstützt seit Februar 2012 noch keine binären Nachrichten. Es gibt auch kommerzielle Lösungen wie PusherApp, die sich einfach in jede Webumgebung integrieren lassen, indem sie eine HTTP-API zum Senden von WebSocket-Nachrichten an Clients bereitstellen. Aufgrund der zusätzlichen HTTP-Anfrage entsteht im Vergleich zu einer reinen WebSocket immer ein zusätzlicher Aufwand.

Serverseite

Durch die Verwendung von WebSocket entsteht ein völlig neues Nutzungsmuster für serverseitige Anwendungen. Herkömmliche Server-Stacks wie LAMP sind im HTTP-Anfrage-/Antwortzyklus konzipiert und funktionieren oft nicht gut mit einer großen Anzahl offener WebSocket-Verbindungen. Wenn eine große Anzahl von Verbindungen gleichzeitig geöffnet bleibt, ist eine Architektur erforderlich, die eine hohe Nebenläufigkeit bei geringen Leistungskosten ermöglicht. Solche Architekturen sind in der Regel entweder um Threading oder sogenannte nicht blockierende E/A-Vorgänge ausgelegt.

Serverseitige Implementierungen

Protokollversionen

Das Wire-Protokoll (ein Handshake und die Datenübertragung zwischen Client und Server) für WebSocket lautet jetzt RFC6455. Die aktuelle Version von Chrome und Chrome für Android sind vollständig kompatibel mit RFC6455, einschließlich Binärmitteilungen. Firefox wird ab Version 11 und Internet Explorer ab Version 10 kompatibel sein. Sie können auch ältere Protokollversionen verwenden. Dies wird jedoch nicht empfohlen, da sie bekanntermaßen anfällig sind. Wenn Sie Serverimplementierungen für ältere Versionen des WebSocket-Protokolls haben, empfehlen wir Ihnen, ein Upgrade auf die neueste Version durchzuführen.

Anwendungsfälle

Verwenden Sie WebSocket, wenn Sie eine wirklich niedrige Latenz, also nahezu eine Echtzeitverbindung, zwischen Client und Server benötigen. Beachten Sie, dass dies unter Umständen bedeutet, dass Sie die Erstellung Ihrer serverseitigen Anwendungen überdenken müssen, wobei der Schwerpunkt auf Technologien wie Ereigniswarteschlangen liegt. Hier einige Anwendungsbeispiele:

  • Online-Mehrspielerspiele
  • Chat-Apps
  • Live-Sport-Ticker
  • Soziale Streams in Echtzeit aktualisieren

Demos

Verweise