Websockets und socket.io. Was ist das? Was kann das?

Wenn du dich schon einmal mit interaktiven Webanwendungen beschäftigt hast, dann ist dir sicher bewusst, dass ohne einen schnellen Informationsaustausch zwischen Client und Server, es unmöglich ist zufriedenstellende Ergebnisse zu realisieren. Einen Ansatz dieses Problem zu lösen bieten Websockets.

Im Rahmen dieses Beitrags wird erläutert, wie Websockts einfach mit Hilfe der socket.io Bibliothek und Node.js genutzt werden können.

Zunächst ein Überblick

Im Jahr 2005 kam mit Ajax eine Technologie auf den Markt ohne die das Internet und seine interaktiven Anwendungen heute undenkbar wären. Ein Beispiel: Facebook. Ohne dynamisches Nachladen von Inhalten wäre der Dienst in seiner jetzigen Form nicht realisierbar. Ajax ermöglicht es Daten zwischen Browser und Server asynchron und ohne vollständiges Neu laden des gesamten Inhaltes auszutauschen.

Ajax versendet HTTP Requests und basiert auf dem im Web gewohnten Anfrage/Antwort Prinzip. Dieses Prinzip hat sich etabliert, birgt aber auch einige Nachteile. Durch das Anfrage/Antwort Prinzip ist es über HTTP nicht möglich, ohne vorangegangene Anfrage des Clients, Daten vom Server zu verschicken. Bidirektionale Verbindungen sind folglich über HTTP nativ nicht möglich. Hier setzen Websockets an.

Hinzu kommt, wenn Daten nicht einmalig, sondern erst bei Verfügbarkeit oder regelmäßig vom Server abfragen werden sollen, dies vom HTTP Anfrage/Antwort Prinzip nicht berücksichtigt wird. Das bedeutet, es gibt keinen nativen Mechanismus, um kontinuierliche Abfragen mittels HTTP zu realisieren. Im Laufe der Zeit wurden einige Methoden, die zum Teil auf Ajax basieren, entwickelt, um dieses Problem zu lösen.

Diese werden im Folgenden kurz erläutern:

  • Polling.
    In regelmäßigen Intervallen sendet der Client HTTP-Anfragen an den Server. Der Server antwortet auf jede Anfrage. Sollte es keine aktuellen Daten geben, sendet der Server eine leere Antwort. Es braucht kaum erwähnt werden, dass dieses Verfahren bei hoher Anfragelast den Server schnell an Auslastungsgrenzen bringen kann.
  • Long Polling.
    Der Client sendet eine HTTP-Anfrage an den Server. Der Server hält die zugrundeliegende Verbindung möglichst lange offen ehe er eine Antwort sendet. Falls dem Server, in der Zeit in der die Verbindung geöffnet ist, aktualisierte Daten vorliegen sendet er diese als Antwort zurück. Der Client nimmt die Antwort entgegen und sendet unabhängig, ob die Antwort leer war oder Inhalt hatte, eine neue Anfrage an den Server. Dieses Verfahren funktioniert gut, die Anfragelast ist im Vergleich zum Polling gering. Weiterhin besteht das Problem, dass Anfragen immer vom Client angestoßen werden müssen.
  • XHR-Streaming, htmlfile.
    Dies sind weitere Möglichkeiten regelmäßige Abfragen zu realisieren. Auf diese möchte ich hier nicht weitergehen.
  • Websockets

Alle Methoden haben ihre Daseinsberechtigung. Alle Methoden sind weiterhin an den Anfrage/Antwort Mechanismus des HTTP-Protokolls gebunden. Eine Ausnahme sind Websockets.

Was sind Websockets?

Die Grundlage für Websockets ist ein auf TCP basierendes Protokoll, welches parallel zu HTTP auf gleichem Port genutzt werden kann. Im Gegensatz zu HTTP-Anfragen wird die zugrundeliegende TCP-Verbindung beim Websocketsprotokoll offen gehalten.

websocket_function

Funktionsprinzip Websockets (Quelle: eigene Abbildung)

Eine Websocketverbindung wird durch Anfrage eines Clients geöffnet. Server und Client vollziehen über HTTP einen initialen Verbindungsaufbau (Handshake), upgraden auf das Websocketprotokoll und können sich ab diesem Moment gegenseitig in beide Richtungen eventbasiert Daten zusenden. Das Websocketprotokoll verfügt über einen ähnlichen Aufbau wie das HTTP Protokoll, allerdings mit dem Unterschied, dass auf das Versenden von Headern bzw. Meta-Daten bewusst verzichtet wird. Dies reduziert die zu übertragene Datenmenge erheblich und minimiert Übertragungszeiten. Außerdem wird durch den Umstand, dass Daten nicht angefragt werden müssen, sondern direkt gesendet werden können, unnötiger Datenverkehr eingespart.

Einziges Manko, wie bei so vielen Technologien im Web, ist die Kompatibilität, die nicht in allen Browsers ausreichend gewährleistet ist. Während Firefox bereits ab Version 3 und Chrome ab Version 4 mit Websockets umgehen können, ist der Internet Explorer erst ab Version 10 Websocket tauglich.

Zunächst wird im Folgenden gezeigt, welche Arten von Anwendungen mit Websockets denkbar sind.

Websocket Szenarien

Hier eine kleine Sammlung von Szenarien für die Websockets sehr gut einsetzbar sind:

  • „Echtzeit“ Interaktion zwischen Browser- und serverseitigen Webanwendungen (Push/Pull)
  • Echtzeitkommunikation (Chats, Supportanfragen etc.)
  • Browserbasierte Spiele
  • Schnell aktualisierbare Dashboards

Eine Reihe weiterer Beispiele sind denkbar.

socket.io

Socket.io erleichtert das Arbeiten mit Websockets über Node.js, indem es von der Websocket API abstrahiert und die Funktionalität einfacher nutzbar macht. Einen ähnlichen Ansatz verfolgt z. B. jQuery mit seiner Ajax API. Die socket.io Bibliothek wird auf dem Server geladen und stellt anschließend dem Client ein Skript zur Einbindung über einen Tag bereit. Ein weiterer Vorteil, socket.io bietet Fallback Lösungen auf Long-Polling Mechanismen für Browser die Websockets nicht unterstützen. So können ältere Browser, insbesondere der Internet Explorer bis Version 5.5, unterstützt werden. Wer andere serverseitige Plattformen nutzen möchte, dem stehen socket.io Portierungen für Java, C++, Ruby, Perl, Phyton zur Verfügung. Auch auf iOS und Android verwendbare Lösungen stehen bereit.

Praxis: Easy Chat

Als kleines Beispiel wird die Implementierung eines Mulit-User Chats mittels socket.io demonstriert. Hierfür wird ein Webserver mit einer socket.io Instanz benötigt. Dieser Webserver muss außerdem ein Chat-UI, welches vom Webserver ausgeliefert wird, bereitstellen.

Begonnen wird mit dem Webserver und der integrierten socket.io Instanz:

var http = require('http');
var socketio = require('socket.io');
var fs = require('fs');

// Erzeugt einen Node.js Webserver auf Port 1080, der das Chat UI zurückgibt
var app = http.createServer(function (req, res) {
  fs.readFile(__dirname + '/client.html', {encoding : 'utf-8'}, function(err, data) {
      if(err){
          res.writeHead(500, {'Content-Type': 'text/plain'});
          res.end(err);

      }else{
          res.writeHead(200, {'Content-Type': 'text/html'});
          res.end(data);
      }
  });
}).listen(1080);

// Initalisiert eine socket.io Instanz und bindet diese an den Webserver
var io = new socketio(app);

// Für jeden Client der sich verbindet wird ein Socket bereitgestellt, über das kommuniziert wird
io.on('connection', function(socket){

    socket.on('message', function(data){
        //nur dem sender des Events zuschicken
        socket.emit('addEntry', data);

        //an alle anderen Client senden
        socket.broadcast.emit('addEntry', data);

    })
});

Es folgt das Chat-UI:

<!DOCTYPE html>
<html>
<head>
	<title>Easy Chat</title>

    <!-- Dieses Skript wird automatisch von der socket.io Serverinstanz bereitgestellt -->
	<script type="text/javascript" src="/socket.io/socket.io.js"></script>
	<script type="text/javascript">
        //Client mit socket.io Server Instanz verbinden (Handshake wird durchgeführt)
        var socket = io('http://localhost:1080');
        var currentEntry = "";
        var name = prompt('Whats your name?');

        //Server sendet den Auftrag einen neuen Chateintrag zu verarbeiten
        socket.on('addEntry', function(data){
            var newEntry = '<strong>' + data.sender + ' (' + data.date +')</strong> ' + data.text + '<br>';
            document.getElementById('content').innerHTML += newEntry;
        });

		function submit(){
            var date = new Date();
            var hours = date.getHours(); var mins = date.getMinutes();
            var message = {
                sender : name,
                date : hours + ':' + mins,
                text : document.getElementById('inputMessage').value
            };

            //Sendet dem Server eine neue Chatmessage
            socket.emit('message', message);
            document.getElementById('inputMessage').value = "";
		}
	</script>
</head>

<body>
	<div id="content"></div>

	<input type="text" value ="" id="inputMessage" />
    <input type="submit" value="senden" onclick="submit()" />
</body>

Übergibt man den aufgeführten Serverquellcode der Node.js Laufzeitumgebung und sendet dem Webserver eine Anfrage, dann wird das Chat-UI ausgeliefert. Das Chat-UI initialisiert sofort die Websocketverbindung. Der Chat ist ab diesem Moment einsatzbereit und kann von beliebig vielen Benutzer genutzt werden.

Dieses kleine Projekt, inkl. einer kleinen Anleitung zur Benutzung von Node.js, steht über GitHub zum selbst probieren bereit.

Fazit

Socket.io macht den Umgang mit Websockets, dank des eventbasierten Ansatzes und einfacher API, sehr einfach möglich. Webanwendungen, die in relativer Echtzeit kommunizieren müssen, können effizient und strukturiert entwickelt werden. Durch die weitreichende Kompatibilität der socket.io Bibliothek können auch für ältere Browser reaktionsschnelle Anwendungen realisiert werden.

Was meinst du? Würdest du socket.io bzw. Websockets für kommende Web-Projekte in Betracht ziehen?

Beitragsbild: Eigene Abbildung

Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s