Innovation

Die wirkliche Leistungsfähigkeit von WebSockets

Dino Esposito

 

Dino EspositoDas derzeitige World Wide Web ist nicht als Echtzeitmedium konzipiert. Webanwendungen vermitteln den Eindruck von ununterbrochenem Arbeitsfluss dank klassischer Abruflösungen, die über AJAX oder eventuell über Anforderungen langer Abrufe implementiert werden, wenn die Implementierung effektiv durch Ad-hoc-Bibliotheken wie SignalR und Comet erfolgte. Für die Anforderungen der meisten Anwendungen ist die Abrufmethode eine gute Lösung, auch wenn es client- und serverseitig zu Wartezeiten kommen kann. In diesem Artikel stelle ich Ihnen eine neue Alternative vor – WebSockets.

Die zunehmende Integration zwischen Web- und mobilen Anwendungen mit sozialen Netzwerken führt dazu, dass Verzögerungen bei der Client-/Serverinteraktion weniger toleriert werden. Wenn Sie Ihren Facebook-Status aktualisieren, möchten Sie, dass die Informationen unverzüglich Ihren Freunden angezeigt werden. Ebenso möchten Sie sofort darüber benachrichtigt werden, wenn einem Freund Ihre Beiträge gefallen. Heute sind all diese Features real, und dies ist nur einer der Gründe für den weltweiten Erfolg von Facebook und für die explosionsartige Zunahme des Phänomens sozialer Netzwerke. Letztendlich besteht eine enorme Nachfrage der Lösungs- und Toolentwickler nach einer Implementierung von Echtzeitkommunikation über das Internet.

Die Herstellung absolut verzögerungsfreier Verbindungen zwischen Webclients und -servern erfordert, weit über das HTTP-Protokoll hinauszugehen. Dies ist genau die Eigenschaft, die das WebSocket-Protokoll bietet. Zurzeit ist ein IETF-Standard (Internet Engineering Task Force) für das WebSocket-Protokoll verfügbar. Weitere Informationen hierzu finden Sie unter bit.ly/va6qSS. Eine Standard-API für die Implementierung des Protokolls wird vom World Wide Web Consortium (W3C) für Browser zur WebSocket-Unterstützung formalisiert (siehe bit.ly/h1IsjB). Die Spezifikation hat den Status „Candidate Recommendation“ (Empfehlungskandidat).

Das WebSocket-Protokoll

Das neue WebSocket-Protokoll zielt darauf ab, die strukturelle Einschränkung des HTTP-Protokolls zu überwinden. Aufgrund dieser Einschränkung ist es für die in Browsern gehosteten Webanwendungen ineffizient, die Verbindung zu einem Server über eine permanente Verbindung aufrechtzuerhalten. Das WebSocket-Protokoll ermöglicht die bidirektionale Kommunikation zwischen Webanwendungen und Webservern über einen einzelnen TCP-Socket. Anders gesagt: Mit dem Protokoll kann eine in einem Browser gehostete Webanwendung die Verbindung mit einem Webendpunkt dauerhaft aufrechterhalten, wobei nur minimaler Aufwand entsteht wie Server-, Speicher- und Ressourcenauslastung. Das Endergebnis ist, dass Daten und Benachrichtigungen zwischen Browsern und Webservern ohne Verzögerung und ohne erforderliche Vereinbarung für zusätzliche Anforderungen übertragen werden können. Es mag zwar etwas dramatisch klingen, aber das WebSocket-Protokoll eröffnet völlig neue Möglichkeiten für Entwickler und sorgt dafür, dass abrufbasierte Tricks und Frameworks der Vergangenheit angehören. Nun, das ist nicht ganz richtig.

Verwendung von WebSockets heute

Die Browserunterstützung für das WebSocket-Protokoll wird rasch zunehmen, aber natürlich unterstützen nur die neuesten Browserversionen WebSockets. Benutzer, die ihre Browser normalerweise nicht regelmäßig aktualisieren (oder die aufgrund strenger Unternehmensrichtlinien keine Aktualisierungen vornehmen dürfen), haben das Nachsehen.

Dies bedeutet, dass Entwickler nicht einfach Code basierend auf AJAX-Abruf oder Lösungen langer Abrufe ignorieren können. In dieser Hinsicht ist es wichtig darauf hinzuweisen, dass SignalR – das kommende Microsoft-Framework für Messaging ohne Verzögerung zwischen Browsern und Webservern – eine hervorragende Arbeit dabei leistet, eine permanente Verbindung zu extrahieren, automatisch zu WebSockets zu wechseln und in allen anderen Fällen langes Abrufen zu verwenden. Ich habe SignalR in den letzten Artikeln behandelt und lade Sie nochmals ein, es so schnell wie möglich auszuprobieren, sofern Sie es noch nicht getan haben. SignalR bietet sämtliche Eigenschaften für eine erfolgreiche Bibliothek und ist ein Tool für alle Entwickler und jede Webanwendung.

Wer unterstützt WebSockets heute?

Abbildung 1 zeigt eine kurze Zusammenfassung der Unterstützung für WebSockets, die die meisten gängigen Browser zurzeit bereitstellen.

Abbildung 1 Browserunterstützung für WebSockets

Browser WebSockets-Unterstützung
Internet Explorer WebSockets wird in Internet Explorer 10 unterstützt. Metro-Anwendungen, die mit JavaScript und HTML5 geschrieben wurden, unterstützen WebSockets ebenfalls.
Firefox WebSockets wird ab Version 6 des Browsers unterstützt, der Mitte 2011 veröffentlicht wurde. Eine sehr frühe Unterstützung wurde in Version 4 angeboten, in Version 5 jedoch nicht mehr berücksichtigt.
Chrome WebSockets wird ab Version 14 unterstützt, die September 2011 veröffentlicht wurde.
Opera Unterstützung für WebSockets wurde in Version 11 nicht berücksichtigt.
Safari Unterstützt eine frühere Version des WebSocket-Protokolls.

Mit Ausnahme von Firefox können Sie programmgesteuert auf WebSockets-Unterstützung überprüfen, indem Sie das window.WebSocket-Objekt prüfen. Für Firefox sollten Sie zurzeit noch das MozWebSocket-Objekt prüfen. Ich möchte darauf hinweisen, dass die meisten HTML5-bedingten Funktionen mithilfe einer speziellen Bibliothek wie Modernizr in Browsern (modernizr.com) überprüft werden können. Dies ist der JavaScript-Code, den Sie schreiben müssen, wenn Sie die Modernizr-Bibliothek mit Ihrer Seite verknüpft haben:

if (Modernizr.websockets)
{
  ...
}

Modernizr ist heute womöglich eine ausgezeichnete Wahl, wenn Sie eine WebSocket-Implementierung nutzen möchten, da Polyfills bereitgestellt werden: Code, der automatisch eingreift, wenn ein bestimmtes Feature vom aktuell verwendeten Browser nicht unterstützt wird.

Letztendlich ist das WebSocket-Protokoll ein extrem überzeugendes Feature, das heute nicht einheitlich von Herstellern unterstützt wird. Microsoft unterstützt WebSockets jedoch weitgehend im kommenden Internet Explorer 10 sowie in IIS, ASP.NET, Windows Communication Foundation (WCF) und Windows Runtime (WinRT). Beachten Sie allerdings, dass es noch keine offizielle Standard-API gibt, sodass die frühe Unterstützung großes Interesse darstellt. Als bestmögliche Alternative können Sie WebSockets derzeit über einige Abstraktionsschichten nutzen. Die Verwendung von Modernizr bietet sich an, wenn Sie nahe an der Basis bleiben und Ihren eigenen Code schreiben möchten, mit dem WebSockets aktiviert und deaktiviert werden kann. SignalR ist ein bessere Lösung, wenn Sie ein Framework haben möchten, das eine transparente Verbindung zwischen einem Browser und einem Webendpunkt dauerhaft herstellt – und zwar schnörkellos und ohne die vielen zugrunde liegenden Details kennen zu müssen.

Übersicht über das WebSocket-Protokoll

Das WebSocket-Protokoll für die bidirektionale Kommunikation setzt voraus, dass sowohl die Client- als auch die Serveranwendung die Protokolldetails kennen. Dies bedeutet, dass Sie eine WebSocket-kompatible Webseite benötigen, die einen WebSocket-kompatiblen Endpunkt aufruft.

Eine WebSocket-Interaktion beginnt mit einem Handshake, bei dem zwei Parteien (Browser und Server) gegenseitig ihre Absicht bestätigen, über eine permanente Verbindung zu kommunizieren. Als Nächstes wird ein Bündel von Nachrichtenpaketen über TCP in beide Richtungen gesendet. In Abbildung 2 ist die Funktionsweise des WebSocket-Protokolls dargestellt.

The WebSocket Protocol Schema
Abbildung 2 Funktionsweise des WebSocket-Protokolls

Zusätzlich zu der in Abbildung 2 dargestellten Funktionsweise tauschen beide Endpunkte beim Schließen der Verbindung einen Close-Frame aus, um die Verbindung ordnungsgemäß zu trennen. Der ursprüngliche Handshake besteht aus einer einfachen HTTP-Anforderung, die der Client an den Webserver sendet. Bei der Anforderung handelt es sich um eine HTTP-GET-Nachricht, die als Aktualisierungsanforderung konfiguriert wurde.

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com

Bei HTTP gibt eine Clientanforderung mit dem Updateheader an, dass der Client den Server zum Wechseln auf ein anderes Protokoll auffordert. Mit dem WebSocket-Protokoll enthält die Aktualisierungsanforderung an den Server einen eindeutigen Schlüssel, den er als Beweis, dass die Aktualisierungsanforderung angenommen wurde, verändert zurückgibt. Dies veranschaulicht praktisch, dass der Server das WebSocket-Protokoll versteht. Hier ist ein Beispiel für eine Antwort auf eine Handshakeanforderung:

HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Ein erfolgreicher Statuscode wird stets mit 101 angegeben. Andere Statuscodes werden als Ablehnung für eine Aktualisierung auf das WebSocket-Protokoll interpretiert. Der Server verkettet den empfangenen Schlüssel mit einer festen GUID-Zeichenfolge und berechnet einen Hashwert aus der resultierenden Zeichenfolge. Der Hashwert wird dann Base64-codiert und über den Sec-WebSocket-Accept-Header an den Client zurückgegeben.

Der Client kann auch andere Header wie z. B. Sec-WebSocket-­Protocol senden, um anzugeben, welche Unterprotokolle er einsetzt. Bei einem Unterprotokoll handelt es sich um ein Protokoll auf Anwendungsebene, das anhand des einfachen WebSocket-Protokolls erstellt wurde. Wenn der Server einige der vorgeschlagenen Unterprotokolle versteht, fängt er eins ab und sendet dessen Namen über den gleichen Header zurück an den Client.

Nach dem Handshake können Client und Server ungehindert Nachrichten über das WebSocket-Protokoll senden. Die Nutzlast beginnt mit einem Opcode, der auf die Durchführung des Vorgangs hinweist. Einer dieser Opcodes, insbesondere 0x8, gibt eine Anforderung zum Schließen der Sitzung an. WebSocket-Nachrichten werden asynchron verarbeitet, sodass eine Sendeaufforderung nicht unbedingt eine sofortige Antwort erhält, wie dies bei HTTP der Fall ist. Denken Sie beim WebSocket-Protokoll eher an allgemeine Nachrichten, die vom Client zum Server und umgekehrt gesendet werden, und lassen Sie dabei das klassische Anforderung-Antwort-Muster von HTTP außer Acht.

Die typische URL für einen WebSocket-Endpunkt hat folgende Form:

var myWebSocket =
    new WebSocket("ws://www.websocket.org");

Verwenden Sie das wss-Protokollpräfix, wenn Sie eine sichere Socketverbindung öffnen möchten (sichere Verbindungen sind im Allgemeinen erfolgreicher, wenn Zwischenstellen vorhanden sind). Letztendlich erkennt und behebt das WebSocket-Protokoll das Problem der ursprungsübergreifenden Kommunikation. Ein WebSocket-Client lässt normalerweise das Senden von Anforderungen an die in beliebigen Domänen befindlichen Endpunkte zu, allerdings nicht immer. Jedoch entscheidet der WebSocket-Server, ob die Handshakeanforderung akzeptiert oder abgelehnt wird.

Übersicht über die WebSocket-API

Wie bereits erwähnt, standardisiert das W3C derzeit eine API für das WebSocket-Protokoll, und die Browser holen mit den verschiedenen Entwürfen auf, sobald sie verfügbar werden. Bedenken Sie, dass ein Code, der heute funktioniert, möglicherweise nicht browserübergreifend funktioniert, und – weitaus wichtiger – auch nicht die Garantie besteht, dass er auf dem gleichen Browser ausgeführt werden kann, nachdem eine neue Version auf den Markt gebracht wurde. Sobald Sie über einen funktionierenden WebSocket-Code verfügen, sind Sie jedenfalls fast schon fertig, da jegliche Änderungen, die möglicherweise zukünftig erforderlich sind, sicherlich nur geringfügig ausfallen werden.

Wenn Sie das WebSocket-Protokoll ausprobieren möchten, können Sie websocket.org mit einem Browser aufrufen, der das Protokoll unterstützt. Sie können hierfür zum Beispiel eine Vorschau von Internet Explorer 10 oder eine neue Version von Google Chrome verwenden. Abbildung 3 zeigt das Handshake, wie es von Fiddler nachverfolgt wird.

Real Handshaking Between Browser and Server
Abbildung 3 Echter Handshake zwischen Browser und Server

Wie zu erwarten, erfasst die aktuelle Fiddler-Version (Version 2.3.x) nur HTTP-Datenverkehr. Eine neue Fiddler-Version, die auch WebSocket-Datenverkehr verarbeiten kann, befindet sich zurzeit in der Betaphase.

Die WebSocket-API ist ziemlich einfach. Sie müssen browserseitig eine Instanz der WebSocket-Browserklasse erstellen. Diese Klasse zeigt eine Vielzahl von interessanten Ereignissen, für die Sie passende Handler benötigen:

var wsUri = " ws://echo.websocket.org/";
websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onerror = function(evt) { onError(evt) };

Das onopen-Ereignis wird bei der Verbindungsherstellung ausgelöst. Das onmessage-Ereignis wird ausgelöst, wenn der Client eine Nachricht vom Server empfängt. Das onclose-Ereignis wird nach dem Trennen der Verbindung ausgelöst. Und zum Schluss wird das onerror-Ereignis bei Auftreten eines Fehlers ausgelöst.

Zum Senden einer Nachricht an den Server müssen Sie einfach nur die send-Methode aufrufen, so wie hier angegeben:

var message = "Cutting Edge test: " +
  new Date().toString();
websocket.send(message);

Abbildung 4 zeigt eine Beispielseite, bei der es sich um eine Adaptation des Echo-Beispiels von der Website websocket.org handelt. In diesem Beispiel gibt der Server die empfangene Nachricht einfach an den Client zurück.

The WebSocket Protocol in Action
Abbildung 4 Das WebSocket-Protokoll in Aktion

Wenn Sie an der WebSocket-Programmierung für Internet Explorer 10 interessiert sind, finden Sie weitere Informationen hierzu unter bit.ly/GNYWFh.

Die Serverseite von WebSockets

In diesem Artikel habe ich hauptsächlich nur die Clientseite des WebSocket-Protokolls erläutert. Es versteht sich von selbst, dass Sie zur Verwendung eines WebSocket-Clients einen geeigneten WebSocket-kompatiblen Server benötigen, der die Anforderungen versteht und entsprechend antworten kann. Allmählich tauchen Frameworks zum Erstellen eines WebSocket-Servers auf. Sie können zum Beispiel Socket.IO für Java und Node.js (socket.io) ausprobieren. Wenn Sie nach Informationen zu Microsoft .NET Framework suchen, lesen Sie den Artikel „Web Socket Server“ auf der Seite „The Code Project“ unter bit.ly/lc0rjt. Darüber hinaus steht Microsoft-Serverunterstützung für WebSockets in IIS, ASP.NET und WCF zur Verfügung. Weitere Informationen hierzu erhalten Sie im Channel 9-Video „Building Real-Time Web Apps with WebSockets Using IIS, ASP.NET and WCF“ (Erstellen von Echtzeit-Webanwendungen mit WebSockets mithilfe von IIS, ASP.NET und WCF) unter bit.ly/rnYaw5.

Bratkartoffel, Wärmflasche und WebSockets

Wie viele Leute bereits gesagt haben, ist WebSockets die nützlichste Erfindung seit der Bratkartoffel und der Wärmflasche. Wenn Sie WebSockets erst einmal verstanden haben, fragen Sie sich, wie die Softwarewelt jemals ohne florieren konnte. WebSockets erweist sich für zahlreiche Anwendungen als hilfreich, wenn auch nicht für alle. Für Anwendungen, in denen Instant Messaging eine bedeutende Rolle spielt, können Sie ernsthaft die Erstellung eines WebSocket-Servers und einiger Clients in Erwägung ziehen: Web-, mobile oder sogar Desktopanwendungen. Spiele und Livefeed-Anwendungen sind weitere Bereiche, die vom WebSocket-Protokoll deutlich profitieren werden. Ja, WebSockets ist definitiv das Beste seit Erfindung der Bratkartoffel!

Dino Esposito ist der Verfasser von „Programming ASP.NET 4“ (Microsoft Press, 2011) und „Programming ASP.NET MVC 3“ (Microsoft Press, 2010) sowie Mitautor von „Microsoft .NET: Architecting Applications for the Enterprise“ (Microsoft Press 2008). Esposito lebt in Italien und ist ein weltweit gefragter Referent für Branchenveranstaltungen. Sie können ihm auf Twitter unter twitter.com/despos folgen.

Unser Dank gilt den folgenden technischen Experten für das Lektorat dieses Artikels: Levi Broderick und Brian Raymor.