Platformunabhängige Netztwerkprogrammierung in C++ mit Sockets

0. Infos zu diesem Tutorial

Dieses Tutorial ist schon etwas älter und ich bin nie dazu gekommen es zu vervollständigen. Ich hoffe das ich bei Zeiten dazu kommen werde. Ich veröffentliche jetzt schon mal alles was ich noch von Damals habe und erweitere es dann.

 

1. Einführung

Täglich surfen wir im Internet.
Wir laden uns Dateien runter, laden Bilder hoch,
diskutieren in Forum über diverse Themen...
Wir leben im Internet!

Und dies ist auch ein guter Grund für einen C++ Programmierer (Auch C - ich bin mir nichtmal sicher ob wir überhaupt Klassen brauchen werden :P) zu lernen wie eine eigene Anwendung netzwerktauglich gemacht werden kann. Das möchte ich euch in diesem Tutorial zeigen! Ihr werdet lernen, mithilfe von Sockets platformunabhängige und netzwerkfähige Programme zu schreiben. (Sofern ihr nicht irgendwelche Systemspeziefischen Funktionen oder Bibilotheken wie die WinAPI benutzt ^^) oder werdet lernen wie ihr eine Domain auflösen könnt (d.h. aus einer Domain wie "entwicklerpages.de" eien IP Adresse zu finden - die benötigen wir für eien Verbindung, aber das werde ich später noch erläutern) und einen Funktionsfähigen Clienten (Empfänger) oder Server (Sender) erstellen könnt. Dabei möchte ich das Tutorial in mehrere Teile aufteilen.
Zuerst wollen wir ein wenig Theorie durchnehmen (trocken aber notwendig - zum Glück nicht viel :D)
Wenn wir damit fertig sind, schreiben wir einen ersten Client mit dem wir über eine beliebige IP oder Domain über einen beliebigen Port (ja, ich weiß, ich greife mit den Begriffen ein wenig vor) ansprechen können.
Danach schreiben wir einen Server. Dieser soll am Anfang einfach nur einen String zurückgeben und die Anfrage des Clienten speichern. Später zeige ich euch wie wir bei einem Server mit mehrere Clients auf praktische Weise umgehen können. Wenn wir damit fertig sind schreiben wir einen Chat (vermutlich die erste und einzige Stelle wo wir Klassen benutzen werden). Wir werden uns dann überlegen wie wir den Chatserver direkt in den Chat integrieren können. Zu guter letzt schauen wir uns noch UDP an.
Damit sollte der Ablauf geklärt sein.

 

2. Lizenz/Rechtliches

Ich habe mir sehr viel mühe gegeben dieses Tutorial zu schreiben. Alles was ihr in diesem Tutorial lernt könnt ihr selbstverständlich so benutzen wie ihr es wollt. Im späteren Verlauf benutzen wir eine von mir geschriebene Headerdatei. Auch diese könnt ihr frei und ohne Namensnennung nutzen. Allerdings ist die Benutzung, Weiterentwicklung/Umschreibung, Fusion oder sonstige Tätigkeiten mit allen Beispielen, Codes und Programmen ohne Garantie. Für mögliche Schäden kann ich nicht haften (keine sorge - alle Codes wurden von mir getestet, aber trotzdem). Ihr seid selbst Verantwortlich was ihr damit macht.
Das Tutorial ist jedoch geistiges Eigentum von Nicolas Hollmann (http://www.entwicklerpages.de/) und unterliegt anderen Regeln.
Ihr dürft es gerne kopieren und weiterreichen - ihr könnt es auch ergänzen oder teile entfernen - allerdings müsst ihr immer die Quelle des Originals angeben. (Samt URL/Link zu dem Original auf www.entwicklerpages.de)
Auserdem muss dieser Rechtliche Teil unverändert enthalten sein. Wenn ihr was ergänzt (Ihr könnt mich auch gerkne kontaktieren) dürft ihr gerne den Rechtlichen Teil so erweitern das eure eigene Arbeit auch nach eurem eigenem Willen lizensiert wird. Jedoch darf sich das AUSDRÜCKLICH nur auf euren Teil beziehen. Wenn ihr etwas entfernen solltet (warum auch immer) dürft ihr diesen Teil auch nicht entfernen und müsst AUSDRÜCKLICH klar machen das Teile fehlen, die im Original nachgelesen werden können.

 

3. Etwas trockene Theorie

Endlich geht es los! Allerdings wie angekündigt nur mit Theorie :(
Ihr werdet in diesem Teil einige Grundbegriffe kennenlernen sowie einen stark verallgemeinerten Seitenaufruf in einem Browser kennen lernen. Dabei werde ich allerdings größtenteils nur auf die Kommunikation zwischen Client (Webbrowser) und Server (Der nur eine einfache HTML seite zurückliefert - nicht mehr und nicht weniger, interne Vorgänge lassen wir ausser Acht) eingehen.

Willkommen im Web!
Wenn wir eine Seite (z.B. Google, YouTube oder Entwicklerpages) aufrufen passieren einige Dinge. Gebt ihr in der Adresszeile des Browsers nun z.B. folgendes ein: "http://www.entwicklerpages.de/" werdet ihr innerhalb von Sekunden unsere schöne Startseite mit den Meldungen vom letzten Jahr zu gesicht bekommen. [Anmerkung: Jetzt gibt es garkeine Meldungen mehr tongue-out]  Nun, was aber passiert da alles bei einem solchen Aufruf?
Zuerst muss der Browser wissen welchen Server er aufrufen soll. Das haben wir gemacht als wir in der Adresszeile "entwicklerpages.de" eingegeben haben, oder? Die Antwort lautet jain. Ja, weil er mit dieser Info weis wie er fortfahren soll - Nein weil eine Domain nicht ausreicht. Wir brauchen eine IP Adresse. (IP Adressen dienen im Internet zur Identifikation. Wir können über eine IP Adresse jeden Ansprechen der auch eine hat. Sie wird automatisch von unserem Internetanbieter verteilt.) Toll -.- wie kommen wir jetzt bitte daran? Gibt es keinen Ort wo die eingetragen sind? Und tatsächlich gibt es einen solchen Ort. Um genau zu sein gibt es sogar mehrere Orte. Fast jedes normale System besitzt eine Datei in der wir zuerst nachschauen sollten. (Mac OS X, Linux und unglaublicherweise sogar Windoof [Anmerkung: Bitte die höchst ablenende Haltung gegen Windows verzeihen. Ich musste da gerade meinen PC neu aufsetzten] haben eine solche Datei.) Wo liegt die den? Tja, da haben wir schon das erste Problem: das hängt ganz vom System ab. Und ausserdem stehen in der Datei natürlich längst nicht alle Domains. Um genau zu sein wird bei den meisten nur etwas ähnliches wie "127.0.0.1 localhost" drin stehen (Und ein paar Zusatzinformationen, etc.). Ist ja auch denkbar: Ständig werden neue Domains gekauft oder alte auf eine neue IP Adresse umgeleitet. Ausserdem gibt es verdammt Viele. Die Datei müsste riesig sein, wenn alle darin aufgezeichnet werden sollen. Vielmehr kann man die Datei dazu benutzen, wenn man einen lokalen Server wie XAMPP benutzt, sodass man ihn z.B. über "meineseite.de" aufrufen kann. Das gilt den aber wirklich nur für den eigenen Rechner. Also muss es noch einen anderen Ort geben, wo wir die Domain "auflösen" können (Ja, man nennt das auflösen).
DNS .... was ist das?
DNS steht in diesem Fall nicht für Desoxyribonukleinsäure sondern Domain Name System. Und das ist auch unsere Lösung.
Ich will jetzt nicht zu weit abschweifen, deswegen mache ich es kurz: Es gibt mehrere Orte bei denen der Browser nachschauen muss, wenn er eine Domain auflösen will. Glücklicherweise gibt es in sogut wie jedem System eine Funktion die das für uns erledigt. Wir müssen diese nurnoch Aufrufen und schon bekommen wir die IP Adresse die wir brauchen. Lange rede kurzer Sinn.
Super jetzt haben wir die IP von Entwicklerpages, was nun? Können wir endlich den Server anbetteln, dass er uns eine Webseite zurückliefert die wir anzeigen können? Auch hier muss ich weider sagen jain. Nein, weil für eine Verbindugn benötigen wir noch einen sogennanten Port. Was ist den das schon wieder? Port heist auf deutsch "Hafen" was das ganze eigentlich auch schon erklärt. Ein Port ist ein (virtueller) Hafen über den wir den Server erreichen können. Aus dem vorheriegen Satz habt ihr vermutlich schon erkennen können das wir einen offenen Port beim Server suchen. Firewalls schliessen aber alle nicht benutzten Ports. Auserdem wird uns der Server nur eine Seite zurückliefern, wenn wir den Port ansprechen, hinter dem das Serverprogramm auf uns wartet. Es gibt Ports von 0 bis 65535, also welches ist der richtige? Glücklicherweise war das nur das nein vom jain. Das Ja betrifft die Tatsache, das wir wissen das es der Port 80 ist.
Suuuuperr!
Nur woher wissen wir das bittesehr?

Ganz einfach: Theoretisch könnten wir jeden Port für ein eigenes Programm benutzen, allerdings gäbe es dann in der Praxis Probleme wenn z.B. Firefox Port 20 benutzt, Chrome 30, IE 35 und Safari die 40. Wenn man einen Server hat müsste man auf alle diese Ports acht geben. Auserdem gibt es ja noch andere Anwendungen auf Servern, z.B. um eine Datei hochzuladen. Würde man das auf Port 10 legen und auf einmal kommt ein neuer Browser der genau die 10 benutzt, müsste man alles wieder ändern. Aus dem Grund [Anmerkung: Es geht darum, das die Wahl der Ports nicht unbedingt vom Program sondern auch vom verwendeten Protokoll (HTTP, HTTPS, FTP, etc.) abhängt] gibt es ein paar Vereinbarungen die man bei einer eigenen Software einhalten sollte. Der Port für Webseiten (HTTP) im Internet ist die 80. Es gibt noch viele weitere Vereinbarungen, die z.B. auf Wikipedia stehen.
Mit anderen Worten: Wenn ihr ein vollkommen eigenes Programm schreiben wollt (z.B. ein Spiel oder ein Chat) ist es egal welchen Port ihr benutzt sofern der Client auch weiß auf welchem Port er den Server erreichen kann. Ihr müsst zumindestens beim Clienten aber davon ausgehen, das er euch nicht die gewünschten Ergebnisse zurückliefert. Bei Servern sollte der User den Port selbst wählen oder einen Port über 1024 zu benutzen. Damit ermöglicht ihr es Servereigentümern, die euer Programm benutzen wollen, es auf dem selben Server/der selben Domain laufen zu lassen wie ein anderes Programm was normalerweise den gleichen Port benutzt.
Aber nun zurück zu unserem Browseraufruf.
Wir kennen nun die IP und den Port also können wir uns auch verbinden. Um die Verbindung auf zu bauen benutzen wir sogennante Sockets die uns vom Betriebssystem bereit gestellt werden. Über diese Sockets können wir das System fragen ob es eine Nachricht gibt und wir können über ein Socket auch Daten versenden. Wir haben jetzt also unsere Verbindung über ein Socket erstellt. Aber wir können noch so lange warten, bestenfalls bekommen wir einen Timeout vom Server aber keine HTML Datei. Wieso? Weil wir dem Server noch mindestens sagen müssen welche Datei wir wollen. Für gewöhnlich wird dabei noch ein wenig mehr übermittelt. (Cookies, Sprache, etc.)
Da wir hier uns aber um Netzwerkprogrammierung und nicht mit HTTP beschäftigen lasse ich diesen Punkt mal aus.
Denn nun ist es endlich soweit: Nachdem wir unsere Anfrage versendet haben, liefert derServer uns die passende Datei zuürck (Zusammen mit einem Header der dem vom Clienten ähnelt). Nun brauchen wir den Server fürs Erste nicht mehr und schließen die Verbindung. Ende gut alles gut! Unser Browser interpretiert den HTML Code nun für uns und stellt ihn dar.
Damit haben wir den Ablauf einer einfachen Routine auseinander genommen, die wir ständig benutzen. Dabei habe ich mich allerdings nur auf den Clienten bezogen. Doch das soll erstmal reichen! Sobald wir einen lauffähigen Client schreiben können, komme ich nochmal auf den Server zurück.
Damit ist die Theorie ausgetrocknet und wir können endlich mit dem Coden anfangen! laughing