Enterprise Tales

Web Messaging mit WebSockets

Lars Röwekamp und Matthias Weßendorf

Durch den gezielten Einsatz von Messaging-Systemen kann eine modulare Softwarearchitektur aufgebaut werden [1]. Ein Prozess versendet dabei nach seiner Ausführung eine Nachricht, um so zu signalisieren, dass es beispielsweise eine Zustandsänderung gab. Verschiedene serverseitige Komponenten können nun unterschiedlich auf diese Nachricht reagieren. Doch wie bekommt man eine solche Benachrichtigung vom Server zum Browser? Und dann auch noch ohne Latenz?

Der Server spricht mit dem Browser?

Das HTTP-Protokoll basiert auf dem Request-Response-Modell. Das hat zur Folge, dass ein Webserver nur dann Daten an den Client/Browser sendet, wenn er eine explizite Anfrage gestellt hat. Oder anders formuliert: Ohne Anfrage vom Browser liefert der Server keine Daten aus. In der Web-2.0-Welt ist es allerdings häufig notwendig, die auf dem Server eintreffenden Informationen möglichst schnell und ohne Verzögerung zum Browsern zu schicken. Da es mit dem reinen HTTP (Request/Response) nicht funktioniert, wurden in der Vergangenheit einige Tricks oder Hacks erfunden: Long Polling. Dabei wird ein Request zum Server geschickt. Anders als allgemein üblich, hält der Server den Request wie eine Art Standleitung für einen bestimmten Zeitraum offen und beendet ihn erst, sobald neue Daten verfügbar sind. Konnten keine neuen Daten ermittelt werden, wird der Request nach einem konfigurierbaren Timeout-Intervall geschlossen. Im Browser wird nun der Response verarbeitet, um direkt einen neuen Request zu senden, der auf weitere Daten wartet.

Der Long-Polling-Ansatz scheint zunächst eine geniale Lösung für unser Problem zu sein. Er hat jedoch zwei erhebliche Nachteile: Zum einen werden mehrere vollständige Requests an den Server geschickt, inklusive HTTP Header, um die „Standleitung“ aufrecht zu erhalten. Das verursacht unnötige Daten, die über die Leitungen gehen. Zusätzlich besteht auch hier das bereits angesprochene Latenzproblem. Erreichen den Webserver neue Daten, während der Response zum Client geschickt wird, besteht sogar die Gefahr, dass diese Daten verloren gehen. Es muss also eine bessere Lösung her, wenn möglich sogar als Teil eines Standards.

Der WebSocket-Standard

WebSocket, ein bidirektionaler, Full-Duplex-Kommunikationskanal, tritt an, um die oben genannten Probleme zu lösen. Sobald die Verbindung zwischen einem Browser und dem WebSocket-Server hergestellt ist, können Daten zwischen beiden Parteien beliebig ausgetauscht werden, und das alles über genau einen Kommunikationskanal. Auch Proxy-Server oder Firewalls stellen für WebSocket kein Problem mehr dar. WebSocket wird von zwei Organisationen standardisiert:

  • W3C: WebSocket Client API
  • IETF: WebSocket Protokol

Das clientseitige JavaScript API von WebSocket ist überschaubar. Im Wesentlichen werden vier Callbacks (onmessage, onclose, onerror und onopen), eine Versandfunktion (send()) und die close()-Funktion zum Beenden der Verbindung angeboten (Listing 1). Der Verbindungsaufbau erfolgt mithilfe des Konstruktors. Der onmessage() Callback wird immer dann aufgerufen, wenn der verwendete Server Daten zum Browser schickt. Zum Empfangen muss ein Client lediglich die Verbindung zum Server aufbauen. Es ist nicht notwendig, dass der Client eine Nachricht in Form eines zusätzlichen Requests oder Ähnlichem an den Server schickt. Mit dem aktuellen WebSocket-Standard kann der Browser ebenfalls Binärdaten senden und empfangen.

Listing 1
 
JMS-Nachrichten direkt im Browser empfangen

WebSocket bietet lediglich eine „Pipe“ zu einem (WebSocket-)Server. Der echte Mehrwert entsteht aber erst dann, wenn hochwertigere Protokolle (beziehungsweise deren APIs) mittels WebSocket zum Browser gebracht werden. Bei traditionellen Client-Server-Anwendungen wird ja schließlich auch nicht direkt gegen rohes TCP programmiert, sondern auf andere Protokolle wie JDBC, AMQP oder JMS zurückgegriffen. Listing 2 zeigt beispielhaft die Verwendung das JMS JavaScript API des Kaazing WebSocket Gateways. Die Verbindung zum WebSocket-Server wird durch die StompConnectionFactory-Klasse realisiert, anschließend wird dem Consumer ein MessageListener Callback zum Empfangen von JMS-Nachrichten zugewiesen. Die receiveStockMessages()-Funktion wird aufgerufen, sobald Nachrichten vom JMS Broker (z. B. Tibco EMS oder Apache ActiveMQ) im Browser eintreffen:

Listing 2
var stompConnectionFactory = new StompConnectionFactory("ws://stockticker.mybank.com")
var connectionFuture = stompConnectionFactory.createConnection(function () {
   if (!connectionFuture.exception) {
     connection = connectionFuture.getValue();
     connection.setExceptionListener(handleException);
     session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
     topic = session.createTopic("/topic/stockticker");

     // JMS Consumer und MessageListener:
     var consumer = session.createConsumer(topic);
     consumer.setMessageListener(receiveStockMessages);
     connection.start();
   }
...
}); 
// Empfangen einer JMS TextMessage
function receiveStockMessages(message) {
   if (message instanceof TextMessage) {
       var body = message.getText();
       ...
   } else if (message instanceof BytesMessage) {
       var body = message.readUTF();
       ...
  }
  ...
}
Fazit und Ausblick

Mit WebSocket können Daten in „Echtzeit“ vom Server zum Browser übertragen werden, ganz ohne Hacks. Der zugehörige Standard wird von etablierten Organisationen vorangetrieben und steht kurz vor seiner Fertigstellung. WebSocket sollte als Treiber verstanden werden, um so hochwertige TCP/UDP-basierte Protokolle im Browser zu nutzen [2]. Entwickler zukünftiger (Web-)Anwendungen können so vorhandenes Wissen, zum Beispiel über JMS [3], nahtlos im Browser anwenden. WebSocket wird mit Sicherheit ein wichtiger Faktor bei der Realisierung von Webanwendungen der nächsten Generation, die den klassischen Desktopanwendungen in nichts mehr nachstehen.

Lars Röwekamp ist Geschäftsführer der open knowledge GmbH und berät seit mehr als zehn Jahren Kunden in internationalen Projekten rund um das Thema Enterprise Computing (Twitter: @mobileLarson).

Matthias Weßendorf arbeitet für die Firma Kaazing. Dort beschäftigt er sich mit WebSocket, HTML5 und weiteren Themen rund um das Next Generation Web. Er bloggt regelmäßig auf http://matthiaswessendorf.wordpress.com (Twitter: @mwessendorf).

Geschrieben von
Lars Röwekamp und Matthias Weßendorf
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.