Verbindungen von Rechnern unter Java aufzubauen ist ein Kinderspiel – somit ist die Netzwerkprogrammierung, die heutzutage noch aufwändig und kompliziert ist, schnell erledigt. Für Sun Microsystems sind Netzwerke das zentrale Computerthema, deshalb hat die Firma den Slogan „The Network is the Computer“ gleich als Warenzeichen eingetragen.
- Host & IP
Ein am Netzwerk angeschlossener Rechner heißt Host. Jeder Host bekommt eine eigene IP-Adresse, sodass er eindeutig im Netz identifiziert ist. Als IP-Adressen sieht die Version IPv4 eine 32-Bit-Zahl vor und das neuere IPv6 eine 128-Bit-Zahl. Da IP-Adressen wie 195.190.9.30 (IPv4) oder 2001:252:0:1:2008:6 (IPv6) nicht leicht zu merken sind, werden Hostnamen statt der IP-Nummern verwendet. Symbolische Namen haben noch einen weiteren Vorteil, die IP-Adresse kann sich ändern ohne dass der Benutzer davon etwas mitbekommt. Die Zuordnung zwischen Name und IP-Adresse übernimmt ein Dienst namens DNS (Domain Name Service).
Kommunizieren zwei Applikationen via Internet miteinander, tauschen sie Datenpakete aus. Der Datenstrom einer Anwendung wird vom Netzwerkstack in viele kleine Pakete zerlegt. Jedes Paket macht sich dann, unabhängig von den anderen, im Netzwerk auf die Reise zum Empfänger. Der wichtigste Standard für die Vermittlung eines Pakets ist das Internet Protocol (IP).
Ein IP-Paket ist ein Bytefeld, was aus einem Körper und Zusatzinformationen besteht. Die Weiterleitung der Pakete von einem Rechner zum nächsten wird von einem Router übernommen.
IP ist ein verbindungsloses Protokoll. Das bedeutet, dass Pakete verloren gehen, beschädigt, doppelt oder in der falschen Reihenfolge ankommen können. Und so nutzen Applikationen wie Webbrowser oder Email-Clients nicht direkt das Internet Protocol, sondern ein komfortableres Transportprotokoll, was eine Schicht über den IP-Protokollen liegt: das Transmission Control Protocol (TCP).
- TCP
Transmission Control Protocol (TCP) kümmert sich um die korrekte Reihenfolge der Pakete und fordert sie bei Verlust erneut an. Weil TCP und IP häufig gemeinsam Anwendung finden, entstand die Bezeichnung TCP/IP. TCP ist aber nicht das einzige Protokoll, das über der IP-Vermittlungsschicht sitzt.
Wenn wir mit der Netzwerk-API von Java programmieren, bekommen wir von der Transport- und Vermittlungsschicht nichts mit. Unser Programmiermodell basiert auf Sockets, die eine API zur TCP-Ebene darstellen. Und da IP unter TCP liegt, befinden sich Einstellungen auf der Vermittlung- und Router-Ebene außerhalb unseres Einflussbereichs.
- HTTP
Das Hypertext Transfer Protocol (HTTP) dient der Adressierung der Objekte über die Internetadresse, es wickelt die Interaktion zwischen Client und Server ab und sorgt für die Anpassung der Formate zwischen Client und Server. Die Kommunikation erfolgt über das Request-Response-Verfahren bei dem der User über die vorher hergestellte TCP-Verbindung einen Request an den Server sendet. Dieser antwortet mit einem Response, der immer einen HTTP-Status-Code enthält. Aus einem solchen Status-Code kann hervorgehen, dass eine Transaktion abgeschlossen ist oder dass der entsprechende Server nicht erreicht werden kann. Werden Dokumente wegen falscher oder ungültiger Internetadressen nicht gefunden, beinhaltet der Status-Code eine Fehlermeldung, die vom Browser angezeigt wird.
- URL
Die Uniform Resource Locator (URL) ist das Adressenformat für eine Ressource im Web. Die Angaben beginnen mit einem Schema (auch Protokoll genannt), es folgen Doppelpunkt und weitere Angaben wie der Servername und ein Pfad auf das Verzeichnis. Das Protokoll bestimmt die Zugriffsart, und das meistverwendete Protokoll ist HTTP, mit dem auf Inhalte des Webs zugegriffen wird. Die URL-Verbindungen sind schon High-Level-Verbindungen, und wir müssen uns nicht erst um Übertragungsprotokolle wie HTTP oder – noch tiefer – TCP/IP kümmern. Aber alle höheren Verbindungen bauen auf Sockets auf, und auch die Verbindung zu einem Rechner über eine URL ist mit Sockets realisiert.
- DNS
Der Empfänger von IP Pakete ist ein Rechner, der im Netz durch eine Kennung, die numerische IP-Adresse, identifiziert wird. Diese Zahl ist für die meisten Menschen schwer zu behalten, weshalb oft der Hostname Verwendung findet, um einen Rechner im Internet anzusprechen. Die Konvertierung von Hostnamen in IP-Adressen übernimmt ein Domain Name Server (DNS). Baut eine Anwendung – etwa ein Internet-Browser – eine Verbindung zu einem Rechner auf, so hilft eine Betriebssystemfunktion, die IP-Adresse für den Rechnernamen zu ermitteln. An diese Adresse kann dann im nächsten Schritt eine Webanfrage gestellt werden.
- OSI-Schichtenmodell
- Schicht 1: Bitübertragungsschicht (engl.: Physical Layer)
Die Bitübertragungsschicht ist für die Übertragung der Bitströme über das Übertragungsmedium (Kabel, Funk) zuständig. Hier werden Übertragungsmedium (Kupfer, Glasfaser, Funk), die Funktion der einzelnen Leitungen (Datenleitung, Steuerleitung), die Übertragungsrichtung (simplex: in eine Richtung / halb-duplex: abwechselnd in beide Richtungen / duplex: gleichzeitig in beide Richtungen), Übertragungsgeschwindigkeit festgelegt. Beispielgeräte, die dieser Schicht zugeordnet werden sind Netzwerkkarte und Hub.
- Schicht 2: Sicherungsschicht (engl.: Link Layer)
Die Aufgabe der Sicherungsschicht ist der zuverlässige Austausch von Datenpaketen zwischen den Systemen. Sie wird in zwei Unterschichten unterteilt: in die MAC-Schicht (Medium Access Control), die an die Bitübertragungsschicht (Schicht 1) grenzt und in die LLC-Schicht (Logical Link Control), die an die Netzwerkschicht (Schicht 3) grenzt. –
Die Mac-Schicht regelt die Nutzung der Übertragungsmedien und schreibt die physikalische Sende- und Empfangsadresse in das Protokoll der Datenpakete. Die LLC-Schicht teilt den Bitdatenstrom in Datenrahmen (frames) und führt eine Fehlererkennung und -korrektur durch. – Beispielgeräte, die dieser Schicht zugeordnet werden sind Bridge und Switch.
- Schicht 3: Netzwerkschicht (engl.: Network Layer)
Die Netzwerkschicht steuert den Austausch von Datenpaketen, da diese nicht direkt an das Ziel vermittelt werden können und deshalb mit Zwischenzielen versehen werden müssen. Die Datenpakete werden dann von Knoten zu Knoten übertragen bis sie ihr Ziel erreicht haben. Um das umzusetzen zu können, identifiziert die Netzwerkschicht die einzelnen Netzknoten, baut Verbindungskanäle auf und wieder ab und kümmert sich um die Wegsteuerung (Routing) und die Datenflusssteuerung. – Beispielgerät, dass dieser Schicht zugeordnet wird ist ein Router.
- Schicht 4: Transportschicht (engl.: Transport Layer)
Die Transportschicht ist die oberste Schicht des Transportsystems (Schicht 1 bis 4) und ist die Schnittstelle zum Anwendungssystem (Schicht 5 bis 7). Die Transportschicht wandelt die Datenpakete laut Protokoll-Informationen um und sorgt für die richtige Zusammensetzung der Pakete beim Empfänger. – Protokolle, die in dieser Schicht genutzt werden: TCP, UDP, SCTP
- Schicht 5: Sitzungsschicht (engl.: Session Layer)
Die Sitzungsschicht ist die unterste Schicht des Anwendungssystems (Schicht 5-7) und baut logische Verbindungen zwischen Sender und Empfänger auf, kontrolliert diese und beendet sie wieder. – Folgende Dienste können in den Schichten 5-7 genutzt werden: FTP, Telnet, SMTP
- Schicht 6: Präsentationsschicht (engl.: Presentation Layer)
Die Präsentationsschicht fungiert als Dolmetscher, indem sie die Datenpakete in das jeweilige Format des Sender- oder Empfängerknotens übersetzt. Datenkompression- und verschlüsselung gehören auch zu ihren Aufgaben. – Formate und Codierungen dieser Schicht: ASCII, JPEG, HTML, Unicode
- Schicht 7: Anwendungsschicht (engl.: Application Layer)
Die Anwendungsschicht ist die Schnittstelle zur eigentlichen Benutzeranwendung. Hier werden die Netzwerkdaten in vom Benutzer verwendbare Daten umgewandelt. – Beispielanwendungen: Google Chrome, Outlook Express
- Wie programmiert man ein Online-Programm?
Ein Socket dient zur Abstraktion und ist ein Verbindungspunkt in einem TCP/IP-Netzwerk. Werden mehrere Computer verbunden, so implementiert jeder Rechner einen Socket: Derjenige, der die Verbindung initiiert und Daten sendet, einen Client-Socket und derjenige, der auf eingehende Verbindungen horcht, einen Server-Socket. Es lässt sich in der Realität nicht immer ganz trennen, wer Client und wer Server ist, da Server zum Datenaustausch ebenfalls Verbindungen aufbauen können. Doch für den Betrachter von außen ist der Server der Wartende und der Client derjenige, der die Verbindung initiiert. Damit der Empfänger den Sender auch hören kann, muss Letzterer durch eine eindeutige Adresse als Server ausgemacht werden. Er bekommt also eine IP-Adresse im Netz und eine ebenso eindeutige Port-Adresse. Der Port ist so etwas wie eine Zimmernummer im Hotel. Die Adresse bleibt dieselbe, aber in jedem Zimmer sitzt jemand und erledigt seine Aufgaben. Jeder Dienst (Service), den ein Server zur Verfügung stellt, läuft auf einem anderen Port. Eine Port-Nummer ist eine Ganzzahl und in die Gruppen »System« und »Benutzer« eingeteilt. Die so genannten Well-known System Ports liegen im Bereich von 0 bis 1023. Die User-Ports umfassen den restlichen Bereich von 1024 bis 65535. Eine wichtige Port-Nummern ist zum Beispiel 80 für Webserver.
Nachdem der Socket eingerichtet ist, kann er auf hereinkommende Meldungen reagieren. Mit der blockierenden Methode accept() der ServerSocket-Klasse nehmen wir genau eine wartende Verbindung an. Nun können wir mit dem zurückgegebenen Client-Socket genauso verfahren wie mit dem schon programmierten Client. Das heißt: Wir öffnen Ein- und Ausgabekanäle und kommunizieren. In der Regel wird ein Thread den Client-Socket annehmen, damit der Server schnell wieder verfügbar ist und neue Verbindungen annehmen und verarbeiten kann.
Wichtig bleibt zu bemerken, dass die Konversation nicht über den Server-Socket selbst läuft. Dieser ist immer noch aktiv und horcht auf eingehende Anfragen. Die accept()-Methode sitzt daher oft in einer Endlosschleife und erzeugt für jeden Hörer einen Thread. Die Schritte, die also jeder Server vollzieht, sind folgende:
- Einen Server-Socket erzeugen, der horcht.
- Mit der accept()-Methode auf neue Verbindungen warten.
- Ein- und Ausgabestrom vom zurückgegebenen Socket erzeugen.
- Mit einem definierten Protokoll die Konversation unterhalten.
- Stream von Client und Socket schließen.
- Bei Schritt 2 weitermachen oder Server-Socket schließen.
Soll der Server nur eine gewisse Zeit auf einkommende Nachrichten warten, so lässt sich ein Timeout einstellen. Dazu ist der Methode setSoTimeout() die Anzahl der Millisekunden zu übergeben. Nimmt der Server dann keine Fragen entgegen, bricht die Verarbeitung mit einer InterruptedIOException ab. Kommt es zu einem Verbindungsaufbau, erfragt der Server die Kommunikationsströme, um mit dem Client Daten auszutauschen. Diese einfachen byte-orientierten InputStream- und OutputStream-Ströme erweitern wir zum Scanner und PrintWriter, sodass wir Zeichenketten statt roher Bytes lesen und schreiben können. Kommen die Bytes der Zeichenkette nicht an, wartet der Server ewig auf seine Daten und ist unterdessen blockiert. Nach dem Senden ist das Protokoll beendet, und die Verbindung zum Client kann unterbrochen werden. Durch die Endlosschleife ist der Server bereit für neue Anfragen.
Auf der anderen Seite steht der Client, der aktiv eine Verbindung zum Server aufbaut. Er nutzt ein mit Internet-Adresse und Port initialisiertes Socket-Objekt, um den ein- und ausgehenden Datenstrom zu erfragen. Der Client wartet auf das Ergebnis und gibt es auf dem Bildschirm aus. Nach der Kommunikation wird die Verbindung geschlossen, um die nötigen Ressourcen wieder freizugeben.
Ein anderer Punkt ist die Tatsache, dass Server im Allgemeinen multithreaded ausgelegt sind, damit sie mehrere Anfragen gleichzeitig ausführen können. Der Server erzeugt nicht pro Anfrage einen Thread – dies ist relativ teuer –, sondern nimmt die Threads aus einem Thread-Pool. Mit der Thread-Pool-Klasse aus der Java-Bibliothek lässt sich die Aufgabe vorzüglich bewältigen.
- Fazit
Wenn man auf einer Java Version programmiert und das Programm mit einer anderen Java Version ausgeführt wird kommt es zu Anzeigefehlern. Bei Netzwerkprogrammierung muss auf die Eingabe (Scanner) geachtet werden. Zuerst muss in einer Variabel die Eingabe gespeichert werden bevor diese verglichen wird.
- Anhang
- Quellen
http://www.itwissen.info/HTTP-hypertext-transfer-protocol-HTTP-Protokoll.html
http://openbook.rheinwerk-verlag.de/javainsel9/javainsel_21_009.htm#mj79da1cdf9f3c74dd63bb1dea9a5ec49chttps://www.netzwerke.com/OSI-Schichten-Modell.htm
https://www.elektronik-kompendium.de/sites/kom/0301201.htm
http://web.informatik.uni-bonn.de/IV/strelen/Lehre/Veranstaltungen/prak2000/javanet.pdf
http://www.inf.fu-berlin.de/lehre/SS03/aws/network.pdf
- Beispielprogramm
- Bilder
erstellt von Fabian Frauenberger am 26.02.2018