Nutzung von echtem Server-Push mit dem WebSocket-Protokoll

Echtzeitchat mit Node.js und Socket.IO
Kommentare

Was wäre heute eine Anwendung, ohne die bekannten In-App Notifications? Neue Chatnachricht, neuer Artikel oder im Allgemeinen eine neue Benachrichtigung – oft symbolisiert durch ein kleines Icon mit einer Zahl zur Anzeige, wie viele neue Nachrichten uns erwarten. Kaum mehr wegzudenken und ständig verfügbar, auch ohne dass man eine Seite neu laden muss. Und das Ganze natürlich in Echtzeit. Wie das geht? WebSocket für Echtzeitkommunikation lautet das Zauberwort.

In der heutigen Zeit haben wir alle sicher schon mal ein Real-Rime-Collaboration-Tool genutzt, ein Werkzeug, um in Echtzeit gemeinsamen mit anderen Personen ein Dokument zu editieren. Als Paradebeispiel sei hier Google Docs genannt, aber mittlerweile auch Office-Web-Apps wie Word Online. Je mehr Leute dabei sind, umso mehr bunte Marker springen munter in einem Dokument herum, fügen neue Texte ein oder ändern bestehende. Dass alles passiert in Echtzeit.

Prinzipiell gibt es verschiedene Möglichkeiten, das gemeinsame Editieren von Dokumenten zu ermöglichen. Die erste Möglichkeit ist ein typisches Intervallpolling, also das Senden einer Anfrage mit der Bitte um Aktualisierung zum Server in einem bestimmten Intervall. Das heißt, dass wir beispielsweise alle 10 Sekunden eine HTTP-Anfrage zum Server schicken und als Antwort die Änderungen oder das komplette Dokument bekommen. Wirklich Echtzeit ist dies aber nicht, da wir bis zu 10 Sekunden (plus die Zeit zum Verbindungsaufbau und Übertragen der Daten) warten müssen, um neue Änderungen zu erhalten. Das Chaos, das hier in einem gemeinsamen Dokument entstehen würde, kann man sich sicherlich denken. Spaß sieht anders aus.

Die zweite Möglichkeit ist die Nutzung von HTTP Long Polling. Hier schickt der Client eine Anfrage zum Server. Der Server hält die Verbindung so lange offen, bis tatsächlich eine Nachricht eintrifft, und beantwortet die Anfrage. Ist dies geschehen, baut der Client sofort wieder eine neue Verbindung zum Server auf, bis die nächste Nachricht zur Verfügung steht. Die Nachrichten stehen so schneller als in der ersten Variante zur Verfügung, das Ganze ist aber ineffizient, da mit jeder Anfrage und Antwort HTTP-Header übertragen werden. Auch hier kann man sich vorstellen, dass das für das Editieren eines Dokuments nicht wirklich sinnvoll geeignet ist, wenn viele Änderungen vorgenommen werden. Mit großer Wahrscheinlichkeit sind die eigentlichen Änderungen kleiner als der Overhead durch die HTTP-Header.

Die dritte Möglichkeit ist die Nutzung des WebSocket-Protokolls. Dabei handelt es sich um ein Netzwerkprotokoll, das auf TCP aufsetzt, um eine bidirektionale Verbindung zwischen Client und Server aufzubauen. Client und Server können sich so jederzeit über eine Verbindung Daten schicken. Hierbei handelt es sich allerdings nicht um HTTP-Anfragen, d. h. bei der Übermittlung der Daten müssen keine zusätzlichen Header mitgesendet werden. Die Datenpakete sind daher deutlich kleiner und beinhalten genau das, was gesendet wird, also genau unsere Änderungen im gemeinsamen Dokument.

API Summit 2017

Web APIs mit moderner Web-Technologie konsumieren

mit Rainer Stropek (software architects)

API First mit Swagger & Co.

mit Thilo Frotscher (Freiberufler)

Darf ich Ihnen die Hand geben?

Möchte ein Client eine WebSocket-Verbindung zu einem Server aufbauen, schickt der Client eine normale HTTP-Anfrage und sendet zusätzliche HTTP-Header mit (Listing 1), mit der Bitte um ein Upgrade auf das WebSocket-Protokoll.

GET /chat HTTP/1.1
Host: beispiel-seite.de
Connection: Upgrade 
Upgrade: websocket
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://beispiel-seite.de
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13

Unterstützt der Server am Endpunkt /chat das WebSocket-Protokoll, antwortet er mit dem HTTP-Statuscode 101 Switching Protocols (Listing 2). Jetzt können Client und Server über die entstandene WebSocket-Verbindung bidirektional kommunizieren. Dieser Prozess nennt sich auch „WebSocket Handshake“.

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

Doch aufgepasst: Sobald eine WebSocket-Verbindung aufgebaut wurde, passiert – solange niemand Daten übermittelt – auf dieser Verbindung tatsächlich nichts mehr. Das Protokoll beinhaltet kein Keep-Alive. Vielmehr gehen Client und Server davon aus, dass nach dem Verbindungsaufbau die Verbindung steht, d .h. dass in der Zwischenzeit beispielsweise die WLAN-Verbindung schlafen gelegt wird, da die Verbindung keine Aktivität aufweist. Erst wenn einer der Teilnehmer versucht Daten zu senden, kann erkannt werden, dass die Verbindung nicht mehr existiert und neu aufgebaut werden muss. Vorteilhaft ist dies natürlich für mobile Endgeräte. Eine Verbindung, die keine Aktivität hat, verbraucht keine CPU-Kapazitäten und leert auch nicht den Akku.

Bevor wir nun anfangen, einen Keep-Alive-Mechanismus oder den Reconnect selbst zu implementieren, existieren in der freien Wildbahn einige Bibliotheken, die uns diese Arbeit abnehmen und ein paar Schmankerl zusätzlich bieten. In der Node.js-Welt ist Socket.IO eine sehr beliebte Bibliothek zur Umsetzung von Echtzeitdatenübertragung. Die Implementierung ist sehr einfach, aber auch sehr mächtig. Mit Socket.IO kann man von einfachen Chats bis hin zum gemeinsamen Editieren von Dokumenten alles implementieren. Socket.IO abstrahiert dabei das WebSocket-Protokoll und implementiert zusätzliche Features wie Keep-Alive zum Erkennen von Verbindungsabbrüchen mit automatischem Reconnect. Kann Socket.IO keine Verbindung über das WebSocket-Protokoll aufbauen, fällt es auf die Nutzung von HTTP Long Polling zurück. Das ist natürlich, wie eingangs beschrieben, nicht mehr so effizient, aber wir müssen diesen Fallback nicht selbst implementieren, und unser Code funktioniert weiterhin.

Wie wäre es mit einem Plausch?

Im Rahmen des Artikels wollen wir gemeinsam einen kleinen Chat entwickeln, in dem man in Echtzeit kommunizieren kann. Dabei soll der Chat verschiedene Räume anbieten. Jeder Raum kann beliebig viele Chatter aufnehmen. Nachrichten, die in einem Raum geschickt werden, werden an alle im Raum befindlichen Teilnehmer geschickt. Zudem soll dem Chatter eine Liste aller Personen im Raum angezeigt werden. Das Aussehen der Oberfläche ist in Abbildung 1 zu sehen. Das fertige Beispiel ist auf GitHub zu finden.

Als Voraussetzung wird Node.js in einer aktuellen Version benötigt. Zudem erzeugen wir einen Ordner chatSample, in dem wir alle Sources ablegen. In diesem Ordner öffnen wir nun auch eine Kommandozeile und geben folgenden Befehl ein:

npm init -y

Damit wird eine package.json-Datei erstellt, in der wir unsere Abhängigkeiten und Startskripte abspeichern. Als Nächstes benötigen wir folgenden Befehl zum Installieren der benötigten Abhängigkeiten:

npm i --save socket.io bootstrap@4.0.0-alpha.3 concurrently node-static nodemon

Folgende Abhängigkeiten werden installiert:

  • socket.io beinhaltet die zuvor angesprochene Bibliothek zur Abstraktion des WebSocket-Protokolls.
  • bootstrap beinhaltet die nötigen CSS-Dateien von Bootstrap für das entwicklerhübsche Frontend. Wichtig ist hier die Angabe der Version, sodass wir die aktuellste Version installieren.
  • concurrently nutzen wir, um parallele Kommandozeilenbefehle auszuführen.
  • node-static beinhaltet einen kleinen Webserver zum Ausliefern von statischen Dateien. Mit ihm sehen wir das Frontend im Browser.
  • nodemon dient zum Starten unserer Server inklusive einem Live-Reloading-Mechanismus, sobald der Serverquelltext sich ändert.

Der nächste Vorbereitungsschritt fügt in unserer package.json-Datei ein neues Skript ein. Dazu öffnen wir die package.json-Datei und ersetzen den vorhandenen Eintrag scripts mit folgendem:

"scripts": {
  "start": "concurrently \"nodemon src/server/chatServer.js\" \"static .\" \"open http://localhost:8080/src/client/index.html\""
}

Wir nutzen concurrently, um drei Kommandozeilenbefehle gleichzeitig auszuführen (alternativ wären die drei Befehle in drei Kommandozeilen auszuführen). Der erste Befehl startet nodemon mit dem Parameter src/server/chatServer.js. Der Parameter ist die Datei, die von nodemon gestartet und überwacht werden soll. Jegliche Änderung dieser Datei führt zum Neustart des Node.js-Prozesses, sodass unsere Änderungen sofort zur Verfügung stehen. Das spart das Beenden und Neustarten der Kommandozeile.

Da wir auf aufwendige Build-Prozesse verzichten, nutzen wir den zweiten Befehl, um einen Webserver mit node-static im gleichen Verzeichnis zu starten, in dem die package.json-Datei liegt.

Der dritte Befehl öffnet das Frontend im Browser. Da node-static per Standard einen Webserver auf Port 8080 öffnet und unser Frontend unter src/client/index.html zu erreichen ist, ergibt sich der im Skript angezeigte URL http://localhost:8080/src/client/index.html.

Bevor wir das Skript starten können, müssen wir die benötigten Dateien anlegen. Das heißt, wir erstellen einen Ordner src und darin einen Ordner client und einen Ordner server. In den Ordner client legen wir eine index.html-Datei und in den Ordner server eine chatServer.js-Datei. Die Dateien können ohne Inhalt angelegt werden, sodass wir sie gemeinsam mit Leben füllen können. Sind die Dateien angelegt, kann auf der Kommandozeile der folgende Befehl ausgeführt werden:

npm start

Damit wird nun der Server gestartet und das Frontend öffnet sich. Selbstverständlich wird weder im Server etwas passieren noch werden wir im Frontend etwas sehen, da die Dateien leer sind. Aber sie dienen für unser Skript als Grundlage, mit der wir nun arbeiten können. Einzig und allein im Browser müssen wir manuell per F5 bei Änderungen einen Refresh durchführen. Der Server wird durch nodemon automatisch neu starten.

Vorne fangen wir an …

Der Inhalt der index.html-Datei ist in Listing 3 zu finden. Die wichtigsten Stellen sind einmal am Ende des <head>– und <body>-Bereichs. In <head> wird das CSS von Bootstrap geladen, während in <body> einmal die Socket.IO-Bibliothek geladen wird und eine app.js-Datei, in der wir zugleich unseren Client implementieren werden. Daher legen wir nun im Ordner src/client eine neue Datei mit dem Namen app.js an. Dazwischen ist ein HTML-Template zur Definition des Frontends gemäß der Abbildung 1, das wir nun auch sehen, wenn wir den Browser refreshen.

<!DOCTYPE html>
<html>
<head>
  <title>Sample Socket.io Chat</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <link href="../../node_modules/bootstrap/dist/css/bootstrap.css" rel="stylesheet"/>
</head>
<body>
  <div class="container">
    <div class="row">
      <div class="col-md-12">
        <div class="jumbotron">
          <h1 class="display-3">Socket.io Sample</h1>
          <p class="lead">This is a sample application to show the usage of Node.js and Socket.io based on a chat application.</p>
          <hr class="m-y-1">
          <form class="form-inline" id="name-form">
            <div class="form-group">
              <label for="name" class="form-control-label">Please tell me your name:</label>
                <input type="text" class="form-control" id="name" name="name" value="Bob">
            </div>
          </form>
        </div>
      </div>
    </div>
    <div class="row">
      <div class="col-md-3">
        <form id="new-room-form" action="javascript:">
          <div class="form-group">
            <input type="text" class="form-control" placeholder="New room name..." id="new-room-name">
          </div>
        </form>

        <ul class="list-group" id="rooms">

        </ul>
      </div>
      <div class="col-md-6">
        <form id="add-message-form">
          <div class="form-group">
            <input type="text" class="form-control" id="message-text" placeholder="If you've joined a room, type in a message and press enter to send it...">
          </div>
        </form>

        <ul class="list-group" id="message-log">
          <li class="list-group-item">You have to join a room in order to chat with someone.</li>
        </ul>
      </div>
      <div class="col-md-3">
        <h3>Chatters</h3>
        <ul class="list-group" id="chatters">

        </ul>
      </div>
    </div>
  </div>

  <script src="../../node_modules/socket.io-client/socket.io.js"></script>
  <script src="app.js"></script>
</body>
</html>
Abb. 1: Darstellung des Frontends – noch ohne Funktion

Abb. 1: Darstellung des Frontends – noch ohne Funktion

… und wechseln direkt nach hinten …

Schauen wir uns zunächst die Implementierung vom Server an. Dazu öffnen wir die chatServer.js und fügen den Inhalt aus Listing 4 ein.

'use strict';

const socketIo = require('socket.io');

class ChatServer {
  constructor(port) {
    this._port = port;
  }

  start() {
    this._initializeSocketIo();

    console.log('Server is up and running');
  }

  _initializeSocketIo() {
    this._io = socketIo(this._port);

    this._io.on('connection', socket => {
      socket.room = '';
      socket.name = '';

      socket.emit('rooms', this._getRooms());

      socket.on('join-room', msg => this._joinRoom(socket, msg));
      socket.on('change-name', name => {
        socket.name = name;
        this._sendAllChattersInRoom(socket.room);
      });

      socket.on('message', message => this._io.in(socket.room).emit('message', {
        from: socket.name,
        message: message
      }));
    });
  }
}

const server = new ChatServer(8081);
server.start();

Zu Beginn laden wir die Socket.IO-Bibliothek und definieren die neue Klasse ChatServer. Der Konstruktor der Klasse benötigt einen Port, auf dem der Server gestartet werden soll. Die einzige öffentliche Methode start() initialisiert Socket.IO und startet damit den Server.

Dazu übergeben wir der geladenen Bibliothek unseren Port, und schon haben wir einen WebSocket-Server mithilfe von Socket.IO am Laufen. Einfacher gehts nicht!

Socket.IO arbeitet eventbasiert. Daher harmoniert es sehr gut mit Node.js und kann die Stärken von non-blocking I/O ausnutzen. So ist ein einzelner Prozess in der Lage, mehrere tausend oder gar hunderttausend Verbindungen gleichzeitig zu verwalten.

Generell können wir bei Socket.IO mit der Methode on() auf ein Event reagieren. Das erste Event, das uns interessiert, ist das connection-Event. Es findet immer dann statt, wenn ein neuer Client sich verbindet. Im Callback erhalten wir den Client (Socket), der sich verbindet und auf dem wir arbeiten können. Als ersten Schritt initialisieren wir den Raum und den Namen des Sockets als leeren String. Diese Daten werden wir im Anschluss vom Client erhalten.

Als Nächstes können wir mit socket.emit() Daten an genau diesen einen Client übermitteln. Der erste Parameter ist ein Schlüssel zur Identifikation der Daten. Dieser Schlüssel wird auf der Clientseite zu einem Event, das wir wieder per on()-Methode fangen können. Der zweite Parameter sind die eigentlichen Daten. Als Erstes wollen wir also dem Client alle vorhandenen Räume übermitteln. Die Methode _getRooms() (und weitere, bisher nicht definierte Methoden) werden wir im Anschluss entwickeln.

Anschließend implementieren wir mehrere socket.on(), um auf Daten zu reagieren, die uns vom Client geschickt wurden. Aufgepasst: Nutzen wir on() oder emit() auf der socket-Ebene, horchen bzw. kommunizieren wir auch nur genau mit diesem einen Client. Nutzen wir die Methoden stattdessen auf this._io-Ebene, horchen wir auf alle Clients oder senden allen Clients unsere Daten.

Die socket.on()-Methode lauscht auf das Event join-room, das empfangen wird, wenn der Client den Raum wechselt. Das Event change-name tritt ein, wenn der Client seinen Benutzernamen wechselt. Dies vermerken wir in unserem Socket und senden die Namensänderung an alle anderen Clients. Das dritte Event ist das message-Event. Es tritt ein, wenn der Client eine Nachricht schickt, die im Chatraum dargestellt werden soll. Erhalten wir dies am Server, möchten wir diese Nachricht an alle Clients im gleichen Raum schicken.

Socket.IO kennt das Konzept von Räumen und bietet daher die Methode in() an, um eine Nachricht nur an Clients in einem bestimmten Raum zu schicken. Das ist natürlich der Raum, in dem der Client die Nachricht geschrieben hat. Per emit() schicken wir die Nachricht zusammen mit dem Namen des Clients an alle im Raum befindlichen Chatter.

Schauen wir uns als Nächstes die Methode _joinRoom() an, die ausgeführt wird, wenn der Client den Raum wechselt. Der Inhalt ist in Listing 5 zu finden.

_joinRoom(socket, roomName) {
  if (socket.room) {
    socket.leave(socket.room, () => {
      this._io.in(socket.room).emit('chatter-left', socket.name);
      this._internalJoinRoom(socket, roomName);
    });

    return;
  }

  this._internalJoinRoom(socket, roomName)
}

_internalJoinRoom(socket, roomName) {
  socket.join(roomName, () => {
    socket.room = roomName;
    this._io.in(socket.room).emit('chatter-joined', socket.name);
    this._io.sockets.emit('rooms', this._getRooms());
    this._sendAllChattersInRoom(socket.room);
  });
}

In _joinRoom() prüfen wir, ob der Socket sich in einem Raum befindet. Falls ja, nutzen wir die leave()-Methode, um den Raum zu verlassen. Der Callback wird ausgeführt, sobald der Client diesen Raum tatsächlich verlassen hat. Das bedeutet, dass der Socket.IO-Server dem Client das Verlassen des Raums mitteilt und dieser eine Bestätigung schickt. Ist das passiert, schicken wir an alle Clients im alten Raum eine Nachricht, dass ein Client diesen Raum verlassen hat. Danach können wir in den neuen Raum durch den Aufruf der Methode _internalJoinRoom() wechseln.

Das Betreten des Raums passiert nun mit der join()-Methode. Auch wird der Callback ausgeführt, sobald der Client den Raum tatsächlich betreten hat. Dann können wir den aktuellen Raum speichern und allen Clients im Raum eine Meldung schicken, dass der Client den Raum betreten hat. Zusätzlich senden wir allen Clients die aktuellen Räume und welche Chatter sich im aktuellen Raum befinden.

Als Letztes müssen wir noch die Methode _getRooms() implementieren. Ihre Implementierung ist in Listing 6 zu finden. Die Methode _sendAllChattersInRoom() ist zur Übung dem Leser überlassen.

_getRooms() {
  const rooms = {};

  Object.keys(this._io.sockets.connected).forEach(socketId => {
    const socket = this._io.sockets.connected[socketId];

    if (socket.room) {
      rooms[socket.room] = '';
    }
  });

  return Object.keys(rooms);
}

Hier erzeugen wir uns eine Hashmap mit allen Räumen, indem wir über die verbundenen Sockets iterieren. Per Object.keys() wandeln wir die Hashmap in ein String-Array um. Damit sind die Arbeiten am Server abgeschlossen. Schauen wir uns nun das Frontend an.

… und wieder ab nach vorne

Für das Frontend öffnen wir die Datei src/clients/app.js. Der Inhalt ist in Listing 7 zu finden.

!function () {
  'use strict';

  var controls, socket;

  function initialize() {
    initializeControls();
    initializeSocketIo();
  }

  function initializeControls() {
    controls = {
      name: document.querySelector('#name'),
      newRoomName: document.querySelector('#new-room-name'),
      chatters: document.querySelector('#chatters'),
      rooms: document.querySelector('#rooms'),
      messageLog: document.querySelector('#message-log'),
      messageText: document.querySelector('#message-text'),

      nameForm: document.querySelector('#name-form'),
      newRoomForm: document.querySelector('#new-room-form'),
      addMessageForm: document.querySelector('#add-message-form')
    };

    controls.nameForm.addEventListener('submit', function (event) {
      event.preventDefault();
      changeName();
    });

    controls.newRoomForm.addEventListener('submit', function (event) {
      event.preventDefault();
      createRoom();
    });

    controls.addMessageForm.addEventListener('submit', function (event) {
      event.preventDefault();
      sendMessage();
    });
  }

  function initializeSocketIo() {
    socket = io('http://localhost:8081');

    socket.on('connect', changeName);
    socket.on('rooms', refreshRooms);
    socket.on('message', function (message) {
      addMessage(message.message, message.from);
    });
  }

  window.addEventListener('load', initialize);
}();

Zuerst initialisieren wir ein paar Controls, die auf unserer HTML-Seite liegen und essenziell für die Chatnutzung sind. Zudem hängen wir an die drei Formulare der Input-Elemente einen submit Event Listener, sodass wir auf deren Eingaben reagieren können. Wie auch auf der Serverseite werden weitere Methoden im Anschluss implementiert.

Danach folgt die Initialisierung von Socket.IO. Durch die Einbindung der Bibliothek in der HTML-Datei steht uns die globale Funktion io() zur Verfügung. Als Parameter bekommt sie den Endpunkt von unserem Server.

Wie beim Server können wir mit der on()-Methode auf Events reagieren. Das Event connect wird von Socket.IO emittiert, sobald der Client mit dem Server verbunden ist. Ist dies geschehen, schicken wir über die Methode changeName() unseren Namen zum Server.

Das Event rooms haben wir auf Serverseite bereits emittiert. Empfangen wir es hier am Client, wollen wir die Darstellung der Räume aktualisieren. Erhalten wir das Event message fügen wir die Nachricht in unserer Nachrichtenliste ein, indem wir die Methode addMessage() nutzen und ihr die benötigten Parameter übergeben.

Zuletzt hängen wir uns an das load-Event vom Browser, das gefeuert wird, wenn die Seite fertig geladen ist, sodass wir Zugriff auf alle Elemente haben.
Schauen wir uns noch die restlichen Methoden an, die wir in Listing 7 benutzen, aber noch nicht definiert haben. Ein Blick in Listing 8 zeigt deren Implementierungen.

function changeName() {
  var newName = controls.name.value;
  socket.emit('change-name', newName);
}

function createRoom() {
  var newRoom = controls.newRoomName.value;
  changeRoom(newRoom);
}

function changeRoom(roomName) {
  socket.emit('join-room', roomName);
  addMessage('You are now in room ' + roomName);
}

function refreshRooms(allRooms) {
  while (controls.rooms.firstChild) {
    controls.rooms.removeChild(controls.rooms.firstChild);
  }

  allRooms.forEach(function (room) {
    var item = createListItem(room);

    item.addEventListener('click', function () {
      changeRoom(room);
    });

    controls.rooms.appendChild(item);
  });
}

function addMessage(message, from) {
  var text = from ? '<strong>' + from + ':</strong> ' + message : message;
  controls.messageLog.appendChild(createListItem(text));
}

function sendMessage() {
  var message = controls.messageText.value;
  socket.emit('message', message);
  controls.messageText.value = '';
}

function createListItem(text) {
  var item = document.createElement('li');
  item.classList.add('list-group-item');
  item.innerHTML = text;

  return item;
}

Die Methoden createRoom(), changeName() und sendMessage() funktionieren alle nach dem gleichen Prinzip. Sie lesen aus dem <input>-Element den Wert aus und nutzen socket.emit() zum Versenden an den Server, worauf im Server die passende on()-Methode aktiv wird.

Die Methoden refreshRooms() und addMessage() sind der Gegenpart zum Empfangen der Servernachrichten und dienen zum Aktualisieren der Räume und Empfangen von Nachrichten.

Damit sind wir tatsächlich mit der Implementierung schon fertig und haben einen vollständigen Chat, der mit WebSocket in Echtzeit kommuniziert und Räume unterstützt. Abbildung 2 zeigt, wie der Chat in Benutzung und vollständiger Implementierung aussieht.

Zur Übung sind dem Leser die Implementierungen des Empfangs der Events chatter-left, chatter-joined und refresh-chatters überlassen. Ein Blick in das GitHub Repository bietet eine Hilfestellung bei der Implementierung.

Abb. 2: Das Beispiel in Aktion

Abb. 2: Das Beispiel in Aktion

Fazit

Schaut man sich den Code an, der für die Kommunikation zuständig ist, sieht man, dass erstaunlich wenig dafür nötig war. Viel Code drumherum dient zum Aktualisieren der Oberfläche oder Helfermethoden zum Sammeln von Daten. Socket.IO bietet eine sehr einfache Abstraktion des WebSocket-Protokolls, bleibt aber dennoch sehr mächtig und unterstützt uns mit sinnvollen Keep-Alive-Mechanismen mit automatischem Reconnect. Es obliegt vielmehr der kreativen Nutzung, um interessante Echtzeitszenarien umzusetzen. Übrigens, es stehen auch Clientbibliotheken für C# zur Verfügung, um mit Socket.IO zu kommunizieren. Viel Spaß beim Implementieren von Echtzeitszenarien!

Windows Developer

Windows DeveloperDieser Artikel ist im Windows Developer erschienen. Windows Developer informiert umfassend und herstellerneutral über neue Trends und Möglichkeiten der Software- und Systementwicklung rund um Microsoft-Technologien.

Natürlich können Sie den Windows Developer über den entwickler.kiosk auch digital im Browser oder auf Ihren Android- und iOS-Devices lesen. In unserem Shop ist der Windows Developer ferner im Abonnement oder als Einzelheft erhältlich.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -