smile chat: Eine Mehrbenutzer-Netzwerkanwendung in C++ und Java
Dieser Inhalt ist unter einer Creative Commons-Lizenz lizensiert.
Die Ursprünge des smile chats gehen zurück bis 1998. Auch wenn sich die Chat-Software als stabil erwiesen hat und monatelang ohne Ausfall und Neustart funktioniert, so ist sie doch nicht vergleichbar mit Server-Architekturen von heute. Die Architektur des smile chats würde sicherlich anders aussehen, würde der Chat heute von Grund auf neu entwickelt werden.
Es ist daher wichtig, sich daran zu erinnern, dass die im smile chat vorgefundene Architektur unter Umständen nicht zeitgemäß ist. Die heutigen Programmiersprachen und Bibliotheken können effizientere Implementierungen ermöglichen als sie vor mehreren Jahren möglich waren. Dieses Kapitel sollte daher als Einführung in die Architektur verstanden werden, um sie dann in einem nächsten Schritt zu verändern und zu verbessern. Das Kapitel sollte nicht als Einführung gelesen werden, wie heute effiziente Mehrbenutzer-Server entwickelt werden - die Architektur des smile chats ist nicht mehr Stand der Technik.
Entwickler, die sich in die Architektur des smile chats einlesen und einarbeiten, besitzen die notwendigen Kenntnisse, um dann den smile chat um neue Features zu erweitern. Die letzten beiden Abschnitte in diesem Kapitel geben Hinweise und Ideen, welche neue Features in den smile chat eingebaut werden könnten und mit welchen technischen Hilfsmitteln die Architektur verbessert werden könnte.
Der Chat-Server besteht aus rund 10.000 Zeilen C++-Code. Das bezieht nicht die Netzwerkbibliothek ein, die speziell für den smile chat entwickelt wurde und die Netzwerkkommunikation übernimmt. Auf die Netzwerkbibliothek wird in diesem Online-Buch nicht näher eingegangen, da sie für die Entwicklung neuer Features in den allerwenigsten Fällen von Interesse ist. Der Chat-Server als Kommandozentrale und Verwaltung sämtlicher Nachrichten, die über das Internet und die Netzwerkbibliothek zur weiteren Verarbeitung zur Verfügung gestellt werden, ist die wesentlich interessantere Baustelle.
Um eine Übersicht über all den C++-Code zu bekommen, werfen wir einen Blick auf folgendes UML-Diagramm. Es stellt die wichtigsten Klassen des Chat-Servers vor und gibt uns einen ersten groben Überblick über die Server-Architektur.
Die wichtigsten Klassen sind rot dargestellt: In der Klasse manager
werden alle Ressourcen zentral verwaltet. Der Manager weiß Bescheid, welche Räume - Klasse room
- und momentan eingeloggten Chatter - Klasse user
- es gibt.
Wie Sie anhand der Verbindungslinien zwischen diesen drei Klassen erkennen können, verwaltet der Manager zu jedem Zeitpunkt mindestens einen Raum. Einen Raum muss es immer geben, denn irgendeinen Raum müssen Chatter ja betreten, wenn sie sich in den Chat einloggen.
Während es zu jedem Zeitpunkt mindestens einen Raum geben muss, kann es beliebig viele Chatter geben - beliebig viele Chatter im gesamten Chat und pro Raum. Sämtliche eingeloggten Chatter sind in der Klasse manager
gespeichert. Darüberhinaus wird jedoch auch von der Klasse room
auf Chatter verwiesen. Es handelt sich hierbei um die Chatter, die sich im jeweiligen Raum aufhalten. Da es Räume ohne Chatter geben kann - zum Beispiel dann, wenn der Chat leer ist - kann es auch vorkommen, dass es keinen Verweis von room
zu user
gibt.
Die Klasse user
verweist auf mode_standard
oder eine der abgeleiteten Klassen mode_icon
oder mode_photo
. Diese Klassen legen fest, wie Nachrichten, die an einen Chatter gesandt werden, genau aussehen. Da jeder Chatter seinen bevorzugten Mode wählen kann, bekommt jeder Chatter Nachrichten in dem Layout präsentiert, das er bevorzugt.
Zum Nachrichtenaustausch wird die Klasse message
verwendet. Jede Nachricht, die an einen Chatter versandt werden muss, wird in die Klasse message
gepackt und an den Mode des Users geschickt. Sie kommt dann in der Form zurück, wie sie der User erwartet, und kann direkt auf seine Benutzeroberfläche im Client geschickt werden.
Die Klassen user_ex
, permission
und ip
sind relativ kleine Klassen. In der Klasse user_ex
merkt sich der Manager, welche User den Chat kürzlich verlassen haben. Die Klasse permission
wird verwendet, um Ränge und ihre Rechte zu verwalten. Wie Sie sehen wird von der Klasse user
auf die Klasse permission
verwiesen - jeder Chatter besitzt schließlich einen ganz bestimmten Rang mit all seinen Rechten. In der Klasse ip
wiederum wird die IP-Adresse eines Chatters gespeichert.
Die vier Klassen rechts oben im UML-Diagramm werden von verschiedenen anderen Klassen verwendet. Sie werden global instanziiert. Deswegen gibt es keine Verbindungslinien zwischen ihnen und anderen Klassen.
Die Klasse database
stellt eine Schnittstelle zur Datenbank zur Verfügung. Sie verwendet die Klasse profile
, um Profile von Chattern zu laden oder zu speichern. Das ist zum Beispiel notwendig, wenn ein Chatter morpht, seine aktuelle Identität gespeichert und eine neue geladen werden muss.
Die Klasse security
wird verwendet, um Logdateien zu erstellen. Der Chat kann zum Beispiel bei Eingabe bestimmter Wörter automatisch Logdateien anlegen oder Chatter überwachen.
Die Klasse configuration
lädt die Konfigurationsdatei des smile chats und stellt Zugriff auf sämtliche Einstellungen in der Konfigurationsdatei zur Verfügung. Einstellungsmöglichkeiten werden im dritten Kapitel vorgestellt.
Es gibt die Möglichkeit, bestimmte Zeichenfolgen automatisch durch andere zu ersetzen. So kann zum Beispiel eingestellt werden, dass die Zeichenfolge :-) durch ein Smiley in Form einer Grafik ersetzt werden soll. Die entsprechenden Ersetzungen werden in der Klasse replacement
durchgeführt.
Die letzte noch nicht erwähnte Klasse ist html_pending
. Diese Klasse hat folgenden Sinn: Beim Einloggen in den smile chat nimmt ein Chat-Applet im Browser Kontakt zur Klasse manager
auf. Die Klasse manager
erstellt dann eine neue Instanz der Klasse user
und reicht die Verbindung an diese Instanz weiter. Diese Verbindung wird dann zur Steuerung und Kommunikation zwischen dem Server und Client verwendet.
In älteren Browsern - in Browsern, die keine dynamische Veränderung von Webseiten unterstützen - ist es jedoch notwendig, dass eine zweite Verbindung zur Ausgabe von Nachrichten aufgebaut wird. Der Browser baut neben dem Chat-Applet in einem anderen Frame eine Verbindung zum Chat-Server auf. Diese wird ebenfalls von der Klasse manager
in Empfang genommen, jedoch an die Klasse html_pending
weitergereicht. Erst dann, wenn der Manager sowohl eine neue Instanz der Klasse user
erstellt hat als auch eine zweite Verbindung in html_pending
vorliegt, können diese beiden Objekte zusammengefügt werden. Die Klasse html_pending
ist also lediglich zur Unterstützung älterer Browser wie Netscape Navigator 4 gedacht.
Die Klasse user
ist die Klasse, die die Kommunikation mit dem Client abwickelt, nachdem sich ein Chatter eingeloggt hat. So werden sämtliche Eingaben eines Chatters an seine Instanz der Klasse user
geschickt, wo sie dann verarbeitet werden.
Die Klasse user
ist ziemlich groß. Der smile chat besitzt schließlich zahlreiche Features und muss auf eine Vielzahl an Eingaben reagieren. Damit Sie sich möglichst einfach in dieser Klasse zurechtfinden, erhalten Sie einen Überblick über die wichtigsten Methoden. Im Folgenden sehen Sie einen Auszug aus der Headerdatei der Klasse user
.
void on_proto_login(std::string line); void on_proto_authentication(std::string line); void on_proto_nickname(std::string line); void on_proto_password(std::string line); void on_proto_text(std::string line); void on_proto_color(std::string line); void on_proto_room_password(std::string line); void on_proto_morph_password(std::string line); void on_proto_heartbeat(std::string line); void on_cmd_text(std::string& text); void on_cmd_me(std::string& text); void on_cmd_lock(void); void on_cmd_open(void); void on_cmd_hide(void); void on_cmd_show(void);
Methoden, deren Name mit on_proto beginnt, werden aufgerufen, wenn Protokoll-Nachrichten verarbeiten werden müssen. Der smile chat basiert auf einem einfachen textbasierten Protokoll, das zur Kommunikation zwischen Client und Server verwendet wird. Protokoll-Nachrichten können nicht von Chattern erstellt werden. Sie regeln die Kommunikation zwischen Client und Server, transportieren Eingaben von Chattern und Nachrichten, die an Chatter ausgegeben werden sollen. Im folgenden Abschnitt wird Ihnen das Protokoll des smile chats vorgestellt.
Methoden, deren Name mit on_cmd beginnt, werden aufgerufen, wenn ein Chat-Befehl verarbeitet werden muss. Üblicherweise werden on_cmd-Methoden von on_proto_text() aufgerufen - on_proto_text() ist für den Empfang von Eingaben während eines laufenden Chats verantwortlich. Beginnen Eingaben mit einem Punkt - dieser kennzeichnet Chat-Befehle - ruft on_proto_text() für gewöhnlich die entsprechende on_cmd-Methode zur Weiterverarbeitung auf.
Sie finden in der Headerdatei der Klasse user
zahlreiche on_cmd-Methoden - jeder Chat-Befehl hat seine eigene on_cmd-Methode. Während on_cmd_text() eine Textnachricht einfach nur an einen Raum weiterleitet - diese Methode wird dann von on_proto_text() aufgerufen, wenn kein Chat-Befehl eingegeben wurde - führt zum Beispiel on_cmd_me() eine Aktion aus. Diese Methode wird bei Eingabe des Befehls .me aufgerufen.
Wenn Sie einen Blick in die Implementierungen der on_cmd-Methoden werfen, sehen Sie, wie Chat-Befehle im Einzelnen funktionieren und welche Schritte ausgeführt werden.
Nachrichten, die vom Netzwerk kommen, werden von der Netzwerkbibliothek des smile chats an die Klasse user
weitergereicht. Dazu ruft die Netzwerkbibliothek die Methode on_read() der Klasse user
auf und übergibt sämtliche neuen Bytes, die soeben empfangen wurden. Die Klasse user
speichert und interpretiert Bytes, bis eine zusammenhängende Protokoll-Nachricht empfangen wurde. Je nach Protokoll-Nachricht wird dann eine der on_proto-Methoden aufgerufen, die Sie oben bereits gesehen haben.
Das Protokoll des smile chats ist textbasiert und basiert auf Befehlen, die durch einen Zeilenumbruch abgeschlossen werden. Befehle können um Parameter ergänzt werden. Diese werden einfach hinter dem Befehl angegeben, müssen aber durch mindestens ein Leerzeichen vom Befehl und möglichen anderen Parametern abgegrenzt werden. Darüberhinaus müssen Parameter in doppelte Anführungszeichen eingeschlossen werden. Sollte ein doppeltes Anführungszeichen Teil des Parameterwertes sein, muss es durch einen vorausgehenden Backslash entsprechend gekennzeichnet werden.
Die Protokoll-Nachricht, die der smile chat-Server vom Client empfängt, wenn ein Chatter "Guten Tag!" eingibt, sieht wie folgt aus:
TXT "Guten Tag!"
Der Befehl für Eingaben von Chattern ist TXT. Der Client gibt den Text, den der Chatter eingegeben hat, als ersten und einzigen Parameter hinter TXT in doppelten Anführungszeichen an. Hätte der Chatter selbst einfach nur ein doppeltes Anführungszeichen eingeben, sähe die Protokoll-Nachricht wie folgt aus:
TXT "\""
Das smile chat-Protokoll ist vor allem dann wichtig, wenn ein Login eines Chatters stattfindet. Hier müssen zwischen dem Client und dem Server zahlreiche Nachrichten ausgetauscht werden. So muss der Server zum Beispiel wissen, mit welchem Nicknamen sich der Chatter einloggt. Der Client muss wissen, ob der Nickname möglicherweise passwort-geschützt ist. Es kann auch sein, dass der Chatter gebannt ist und ihm ein Login verwehrt wird. Die Befehle der Protokoll-Nachrichten und mögliche Reihenfolgen beim Login stellt folgende Grafik dar.
Beim Login sendet der Client den LGN-Befehl, woraufhin der Server mit CNT reagiert und die Verbindungsaufnahme bestätigt. Je nach Client wird dann auf der eben erstellten Verbindung oder auf einer zweiten Verbindung ein Authentifizierungscode geschickt. Ältere Browser wie Netscape Navigator 4 verwenden eine zweite Verbindung, wie bereits oben im Zusammenhang mit der Klasse html_pending
erläutert.
Je nach Nickname, der mit dem LGN-Befehl mitgeschickt worden war, reagiert der Server seinerseits mit einem LGN-, PWD- oder NCK-Befehl. Die LGN-Antwort des Servers bestätigt ein Login - der Loginvorgang wäre abgeschlossen, und der Client kann mit dem Senden von TXT-Befehlen beginnen. Ein PWD-Befehl bedeutet eine Aufforderung an den Client, ein Passwort einzugeben, da der Nickname passwort-geschützt ist. Der NCK-Befehl wiederum wird gesendet, wenn der eingegebene Nickname nicht den Regeln entspricht und zum Beispiel zu lang ist.
Je nach eingebenem Nickname kann also der LGN-Befehl recht schnell vom Server oder erst nach dem Austausch einiger weiterer Protokoll-Nachrichten geschickt werden. Am Ende eines erfolgreichen Loginvorgangs steht jedoch immer die LGN-Antwort des Servers. Danach kann der Chatter sich im Chat frei bewegen und Texte und Befehle eingeben, die alle mit dem TXT-Befehl vom Client an den Server weitergeleitet werden.
Wenn vom Client die Rede ist, ist genaugenommen der Browser gemeint. Der smile chat besitzt keine eigenes, unabhängiges Programm, das per Doppelklick gestartet und zum Chatten verwendet werden kann. Stattdessen wird der smile chat direkt im Browser verwendet.
Der Client ist nicht der Browser an sich, sondern eine dynamische Webanwendung - bestehend aus HTML-Seiten mit einem Java-Applet und viel Javascript. Das Java-Applet hat eine Doppelfunktion: Für den Chatter stellt es eine Regenbogenschaltfläche dar, über die er per Mausklick seine Textfarbe auswählen kann. Für den Chat ist es das Verbindungsstück zwischen der Webanwendung und dem Server. Denn das Java-Applet, das sich hinter der Farbfläche verbirgt, ist der Kommunikationskanal zum Server.
Wenn ein Chatter Eingaben vornimmt oder Textnachrichten von anderen Chattern erscheinen, dann gelingt das nur im Zusammenspiel zwischen dem Java-Applet und Javascript. Javascript macht aus einer statischen Webseite etwas dynamisches. Wenn eine neue Textnachricht von einem anderen Chatter im Java-Applet ankommt, wird diese vom Java-Applet an eine Javascript-Funktion weitergereicht, die sie wiederum direkt im Browser zum Erscheinen bringt.
Da ältere Browser wie der Netscape Navigator 4 derartige dynamische Veränderungen nicht unterstützen, funktioniert die Ausgabe von Textnachrichten anders: Statt die Textnachrichten zum Java-Applet zu schicken, werden sie direkt in einen Frame des Browserfensters geschickt. Der Chat-Server verhält sich dann wie ein Webserver - nur dass keine Webseite mal eben angezeigt werden soll, sondern Daten vom Chat-Server peu à peu an den Browserframe geschickt werden. Das ist vergleichbar mit einer Webseite, die nie zu Ende geladen wird und genaugenommen auch erst im Moment des Ladens entsteht.
Der Quellcode des Java-Applets ist überschaubar - allein schon deswegen, weil das Java-Applet klein sein muss, damit es schnell geladen wird. Da vor allem der Internet Explorer lange Zeit nur Java in der Version 1.1 von Haus aus unterstützte, ist das Java-Applet in Java 1.1 entwickelt.
Auch wenn das letzte große Update des smile chats länger zurückliegt, so wurden Ideen und Verbesserungsvorschläge kontinuierlich gesammelt. Die folgende Liste soll Anregung genug sein, um den smile chat zum besten Chat überhaupt zu machen.
Würde der smile chat heute von Grund auf neu entwickelt werden, würde seine Architektur anders aussehen. Zum einen würde sich die Frage stellen, ob als Programmiersprache für den Server überhaupt C++ eingesetzt werden sollte. C++-Programme sind zwar extrem schnell und effizient. Sie erfordern jedoch wesentlich mehr Know-How. Ein in Java oder auf der .NET-Plattform entwickelter Server könnte einfacher und schneller entwickelt und gewartet werden als ein C++-Programm.
Zum anderen würde die Achitektur aus mehr Komponenten bestehen - mehr oder weniger unabhängigen Teilen, die zwar alle gemeinsam den Server ausmachen, jedoch leichter ersetzt werden können. Komponenten könnten im Quellcode als Klassen vorliegen, die durch Schnittstellen klar definiert sind. Klassen könnten neu entwickelt und separat getestet werden, um bestmögliche Implementierungen zu finden. Als ausführbare Dateien könnten Komponenten in unterschiedlichen Bibliotheken vorliegen - Klassenansammlungen, die gemeinsam übergeordnete Schnittstellen bereitstellen. Auch diese ließen sich einfacher ersetzen als wenn der smile chat-Server als eine große ausführbare Datei vorliegt.
Der smile chat-Server sollte Verbindungen zu anderen smile chat-Servern aufbauen können. So könnte ein Netzwerk an smile chat-Servern entstehen, in das sich Chatter über beliebige bereitgestellte Server einloggen können und über das gesammte Netzwerk miteinander chatten können. Auch sollte es möglich sein, dass Clients direkt miteinander in Kontakt treten können - ähnlich wie in Peer-to-Peer-Netzwerken. Derartige direkte Verbindungen könnten verwendet werden, um zum Beispiel anderweitige Daten wie Dateien zu übertragen, um nicht unnötigerweise Server zu belasten.
Die Logik des Chats ist bisher ebenfalls in einer Programmiersprache entwickelt und könnte ausgelagert werden. So wird zum Beispiel bei vielen Computerspielen die Logik häufig in einer Skriptsprache implementiert, die speziell für die Logik in Computerspielen entwickelt ist. Man spricht hierbei von Domain-spezifischen Sprachen - Sprachen, die für einen bestimmten Anwendungsbereich entwickelt wurden. Sie sind von Entwicklern, die sich auf die Domain spezialisiert haben, wesentlich einfacher anzuwenden als echte Programmiersprachen wie C++.
Es ist beispielsweise möglich, Regeln in Microsoft Excel auszudrücken. Die Excel-Datei kann dann mit Hilfe einer Komponente, die von verschiedenen Firmen angeboten werden, in den smile chat-Server integriert werden. Die gesamte Logik wird direkt in der Excel-Datei verwaltet. Da viele Anwender Excel-Dateien erstellen können, ließe sich die gesamte Chat-Logik wesentlich schneller und einfacher entwickeln als wenn dies in einer Programmiersprache geschehen würde. Diese Vorgehensweise - die Logik implementiert in Excel-Dateien - wird heutzutage vor allem in der Finanzbranche angetroffen, wo von Haus aus sehr viel mit Microsoft Excel gearbeitet wird und man die Logik nun nicht von Hand in Quellcode übersetzen möchte.
Programmiersprachen wie C++ und Java als auch das .NET Framework bieten mittlerweile sehr große Bibliotheken, die zahlreiche Hilfsmittel zur Verfügung stellen, um Anwendungen schnell zu entwickeln. Auch wenn nicht alles, was heutzutage in der Softwareentwicklung gebraucht wird, bereits in den Bibliotheken gefunden werden kann, so stehen doch sehr viele Klassen und Funktionen zur Verfügung, die nicht mehr selbst entwickelt werden müssen. Neue Versionen des smile chats sollten soviel Code wiederverwenden wie nur irgendwie möglich.
Das Ziel für zukünftige Versionen muss sein, sich auf Kernfunktionen zu konzentrieren. Der smile chat wird von vielen Chattern weger dieser Kernfunktionen eingesetzt. Alles andere ist von geringem Interesse. Chatter sind häufig nicht an der technischen Umsetzung interessiert. Die beste Umsetzung hilft nichts, wenn niemand die Software verwendet. Welche Kernfunktionen wichtiger sind als andere und welche neuen Versionen des smile chats sich durchsetzen werden, bleibt spannend und kann allein von den Chattern über die Zeit beantwortet werden.
Copyright © 2005-2007 Boris Schäling