Und hier kommt jetzt Teil zwei der Vorlesung.
Unter Netzwerkprogrammierung konnte ich mir anfangs noch nicht ganz so viel vorstellen, aber ich wusste was Threads sind und auch was Multi-Threading ist. In diesem Bereich mussten wir mal einen relativ großen Bericht lesen im Fach IT und diesen konnte ich mir relativ gut behalten. Ein Thread ist ein Ausführungsstrang und jeder Thread kann nur eine Aufgabe übernehmen. Je mehr Threads eine CPU hat, desto merh Prozesse können gleichzeitig ablaufen.
Aber erst einmal in der Reihenfolge, wie in der Vorlesung, beginnen wir also mit der Netzwerkprogrammierung.
Möchte man in Kontakt mit einem Programm auf einer anderen Maschine in Kontakt treten, dann ist das gar nicht mal so schwer. Das Gute ist, dass Java sich um alle Low-Level-Netzwerk-Details kümmert. Zusätzlich kommt hinzu, dass das Senden und Empfangen über ein Netz eine einfache Ein- und Ausgabe ist, die einfach nur einen anderen Verbindungsstrom hat.
Begonnen haben wir das Thema mit Sockets. Das hat nichts mit Socken zu tun, auch wenn sich das sehr ähnlich anhört. Es handelt sich um ein Objekt, das Daten aus Netzwerken empfängt, oder an Netzwerke sendet. Auch haben wir darüber gesprochen, über welches Protokoll Java kommuniziert und das ist TCP. TCP baut eine logische Verbindung auf und es gibt (wie wir es gelernt haben) einen sogenannten „handshake“, bevor die Datenübertragung stattfindet. Wenn Datenpakete angekommen sind, bekommt man eine Bestätigung und sie kommen in der Reihenfolge an. Über UDP-Sockets kann auch über Java kommuniziert werden, aber dies ist zum einen nicht sicher und zum anderen verwenden wir auch in der Vorlesung nur TCP-Sockets.
Doch wie funktioniert das ganze wenn man über den Server mit anderen Chatten möchte, zum Beispiel bei WhatsApp?
Der Server muss alle Clients kennen, die Clients nur den Server
Und so funktioniert es:
Der Client A verbindet sich mit dem Server und sagt so viel wie „Server ich möchte eine Verbindung mit dem Chat Dienst aufbauen“ .Der Server, der schon die ganze Zeit auf eine Client-Anfrage gewartet hat, stellt eine Verbindung her und fügt den Client der Liste der Teilnehmer hinzu. Der Server kennt nun den Client A. Danach verbindet sich auch Client B mit dem Chat-Dienst, genauso wie Client A und der Server kennt nun beide Teilnehmer. Wenn Client A nun eine Nachricht an den Chat-Dienst sendet, dann geht diese Nachricht zuerst beim Server ein, und dieser verteilt dann die Nachricht an alle Teilnehmer, auch an den Client A.
Drei Dinge braucht man, um den Client zum Laufen zu bringen:
- Wie man die Verbindung zwischen Server und Client herstellt
- Wie man Nachrichten an den Server sendet
- Wie man Nachricht vom Server empfängt
und so funktionieren diese 3 Dinge:

Um eine Socket-Verbindung herzustellen braucht man, wie man bei Schritt eins indem Bild sehen kann, nur die IP-Adresse und die TCP-Portnummer.
Ein TCP Port ist nur eine 16-Bit-Zahl zur Identifizierung eines bestimmten Programms auf dem Server. Insgesamt gibt es also 2^16 Ports. Das sind 65.535. Davon kann man aber nur die Ports zwischen 1024 und 65.535. nehmen, denn die ersten 1024 sind bereits für bekannte Dienste besetzt. Wir haben jedoch von unserem Professor gesagt bekommen, dass wir nur Portnummern ab 50.000 verwenden sollen. Interessant zu wissen, ist dass jedes Fenster seinen eigenen Port hat, also auch jeder Tab, den man öffnet. Die wohl bekannteste Portnummer ist 80 und wird für http benutzt. Ohne Portnummern könnte ein Server nicht wissen, mit welcher Anwendung sich ein Client verbinden möchte. Außerdem haben intern alle Geräte dieselbe IP Adresse, weshalb die Portnummer nötig ist, damit der Switch auch weiß, an wen er was senden soll. Hierzu wird die IP mit dem internen Port zu einem öffentlichen Port gemappt.
Für die Kommunikation über eine Socket-Verbindung benutzt man Ströme, wie auch in der vorherigen Vorlesung. Also kann man auch genauso einen BufferedReader benutzen. Nur ist der darunter liegende Strom eben mit einem Socket verbunden, anstatt mit einer Datei.
So liest man einen Socket:

oder um das mit Bildchen darzustellen:

und anschließend:

Es ändert sich also nicht allzu viel, außer, dass man den Socket um einen Eingabestrom bitten muss und anstatt einer Datei, die gelesen werden soll, gibt man eben die IP-Adresse des (hier im Beispiel) localhosts und der Portnummer an.
Wenn man eine Datei in einen Socket schreiben möchte, macht man folgendes:

Der Anfang ist derselbe, wie beim Lesen eines Sockets aber danach schreibt man:

Man erzeugt einen PrintWriter, da man ja etwas hineinschrieben möchte und und schreibt dann, das was man schreiben möchte, hinein. Der PrintWriter ist so etwas wie eine Brücke zwischen den Daten in Zeichenform und den Bytes, die er vom Lowlevel-Ausgabstrom des Sockets erhält. Durch den OutputStream (=Ausgabestrom) kann man Strings in die Socket Verbindung schreiben.
Nun kommen wir auch so langsam an das Ende der zweiten Vorlesung, denn jetzt kommen die einleitenden Erklärungen für die Aufgabe, die wir am Ende der Stunde noch abschreiben, aber nicht machen sollten:
Es geht um ein Server-Programm, das so etwas ist, wie ein Tipp des Tages Geber.
Der nachfolgende Programm-Code erzeugt einen Socket und einen BufferedReader und liest eine einzelne Zeile von der Server-Anwendung. Es ist der Code für den Tipp-des-Tages Client


Hier wird noch das Java Paket java.net benötigt. Die Verbindung wird zu unserem localholhost auf Port 4242 hergestellt.
Wie funktioniert es dann einen Server zu schreiben?
um eine Server-Anwendung zu schreiben braucht man ein Paar Sockets (das ist glaube ich das einzige, was Socken und Sockets miteinander verbindet, denn wie bei Socken, braucht man auch für Sockets diesbezüglich zwei Stück). Einen Server-Socket, der auf Client-Anfragen wartet und einen einfachen Socket, der für die Kommunikation mit dem Client benutzt wird.
Server schreiben in 3 Schritten erklärt:
- ServerSocket serverSock = new ServerSocket(4242); Dadurch beginnt die Server-Anwendung auf client-Anfragen auf Port 4242 zu lauschen. Dabei muss der Port geöffnet sein.
- Socket sock = new Socket („190..165.1.103“, 4242); Der Client kennt die IP Adresse und die Portnummer
- Socket sock = serverSock.accept(); Die accept()-Methode blockiert, während sie auf eine Client-Socket-Verbindung wartet. Wenn dann ein Client versucht sich zu verbinden, gibt die Methode einen Socket zurück (! auf einem anderen Port), der die IP-Adresse und Portnummer des Clients kennt. Dieser Socket liegt auf einem anderen Port, als der ServerSocket (also nicht mehr auf 4242), so dass sich auch mehrere Clients mit dem Server verbinden können.
Das war inhaltlich auch der Schluss der Vorlesung, denn anschließend wurden wir noch gebeten den Code in der Vorlesung abzuschreiben. Das werde ich in dem nächsten Eintrag mit einbringen, da ich da auch die Aufgabe erklären und hoffentlich lösen werden.
Bis nächste Woche!