JAVA-C3
Network-Programming
Network Basics
Grundlagen
TCP
UDP
Datagram
IP-Adressen
Port
listen
DNS
Domain-Name
DNS
A- und AAAA-Records
CNAME-Record
Reverse-DNS / PTR-Record
TTL
Windows: DNS und Host
Windows: Firewalls und Ports
HTTPS.SYS
Nginx als Reverse-Proxy
Binding
Lokale Netzwerke und NET
URI
scheme
host
port
path/file
Query
Fragment / Anchor
(01) Hierarchischer URI
(02) Opaque URI
(03) URI mit Sonderzeichen
(04) Normalisierung von URI
(04) Normalisierung von URI
Prüfen auf Gleichheit
a.compare(b)
a.equals(b)
(05) Relative in absolute URIs übersetzen
URL Encoding/Decoding
URL-Encoding
ASCII
Unicode
Codepage
UTF-8
UTF-16
UTF-32
ISO-8859-1
UTF-32
URLDecoder
StandardChartsets.UTF_8
Blocking-I/O
Non-Blocking-I/O
network-java-sockets
@! network-java-nio FEHLT
Client-Server mit Sockets
Unabhängige Java-Programme in Kommunikation über Sockets
Client
Server
@! com.stuelken.java.c1.networking.basics.sockets Version prüfen!
@! com.stuelken.java.***.a7.e50200_clientserver_keyvalue.client KeyValueClientResilient class
@! Das müssten 3 verschiedene Beispiele/Pages sein!
@! Erfordert com.stuelken..ArgumentInterpreter!
@! Sprungmarken für Client, Server, .. ergänzen
Overview
Networking | Overview
Bevor man in die Programmierung von Anwendungen stürzt, welche Netzwerk-Verbindungen verwenden, ist es mehr als ratsam, wenn man die wichtigsten Begriffe und Prinzipien wie mitunter TCP, UDP, localhost, Domains, DNS und dergleichen verstanden hat.
Dieser Themenblock umfasst eine kurze Wiederholung zum Thema Netzwerk-Kommunikation und Begriffen, die für die Programmierung von Bedeutung sind.
Basics
Networking | Basics
Netzwerkkommunikation im ISO/OSI Schichtenmodell
Kaum ein Entwickler muss sich ernsthaft mit den Details von TCP
oder UDP befassen, denn in der Programmierung von Anwendungen werden üblicherweise
auch in Java dann Klassen beispielsweise aus dem Package
java.net
verwendet, um Verbindungen aufbauen zu können. Für die Wahl
der zugehörigen Klassen und das kontrollierte Abfangen von Fehlern
ist es aber erforderlich, dass man Prinzip verstanden hat.
Die Liste an Klassen, welche in der Netzwerk- und Web-Programmierung
in Java eingesetzt wird, ist doch etwas länger.
Netzwerkverbindungen lassen sich mitunter über Klassen
aus java.net,
wie mitunter
java.net.ServerSocket und
java.net.Socket verwendet.
Das Schreiben und Lesen erfolgte früher über
Klassen aus java.io.*,
inzwischen auch über java.nio.*.
Die Verwendung von Frameworks, Libraries und dergleichen kann aber dazuführen, dass manche Entwickler gar nicht mehr in den Kontakt mit der eigentlichen Netzwerk-Programmierung kommen, so dass beispielsweise Verbindungen zu einer Datenbank über den Connector erzeugt werden, ohne dass man sich um die Details kümmern muss.
Das Programm, welches die Daten verarbeitet
Netzwerkprogrammierung ist kein Selbstzweck. Der Programmierung geht im Regelfall voraus, dass ein Programm irgendwelche Daten erzeugt hat und versenden möchte.
Alternativ kann es auch sein, dass man gerade eine Anwendung programmiert, in welcher Programmcode auf eine Anfrage wartet, um auf diesem Weg Daten zu bekommen.
Daten im Web laden und Files verschicken
Zu den vermutlich wichtigsten drei Protokollen zählen HTTP (Hypertext Transfer Protocol), FTP (File Transfer Protocol) sowie TELNET.
Verbindungsaufbau
Ein jeder Computer und dessen Programme, welche über Netzwerkverbindungen und Internetverbindungen Daten austauschen möchten, kommunizieren hierbei üblicherweise über TCP (Transmission Control Protocol) oder aber über UDP (User Datagram Protocol).
Damit UDP und TCP funktionieren können, muss eine Verbindung aufgebaut werden zwischen zwei Ports als Anfangs- und Endpunkt einer Verbindung.
IP Layer
Damit TCP oder UDP überhaupt funktionieren können, ist aber die darunter liegende IP Schicht des Netzwerks mit der Auflösung von Domains in IP-Adressen und Ports erforderlich.
Verbindungsaufbau
Dem IP geht wiederum als darunter liegende Schicht voraus, dass dass die Geräte überhaupt einen Link über Netzwerktreiber haben oder schlussendlich irgendwo in Kabel oder eine WLAN-Verbindung besteht.
Mehr erfahren
Wenn Sie mehr zu den Schichten, engl. Layer, erfahren wollen, informieren Sie sich über das ISO/OSI Schichtenmodelle.
Dieses ist zwar zumeist eher ein Tätigkeitsbereich für Systemadministratoren oder Hardwareentwickler, aber wer immer in der Anwendungsprogrammierung nach Fehlerquellen sucht, wird früher oder später verstehen, dass der Fehler tatsächlich in jeder dieser Ebenen liegen kann.
TCP
Kontrollierte Übertragung
Das TCP Transmission Control Protocol ist ein auf Verbindungen, engl. Connection, basierendes Protokoll, welches einen verlässlichen Datenfluss zwischen zwei Rechnern ermöglicht.
Was man im Mindestumfang wissen sollte:
Verbindungsaufbau
Um Daten via TCP zwischen zwei Rechnern austauschen zu können, wird zuerst einmal eine Verbindung aufgebaut.
Die Reihenfolge bleibt erhalten
Egal, wie und auf welche Weise die Datenpakete über TCP tatsächlich zwischen zwei Rechnern vermittelt werden, so hat TCP einen grundlegende Vorteil:
Die Reihenfolge, in welcher Daten vom Versender über TCP verpackt und verschickt werden, ist schlussendlich beim Empfänger die selbe, in welcher dieser Daten dann bekommen wird.
In Fällen, wo das nicht mehr möglich war, wird ein Fehler ausgeworfen.
TCP ist eine Punkt-zu-Punkt-Verbindung
Jede Verbindung basierend auf TCP beginnt an einem Port als Anfangspunkt einer Verbindung und endet auf einem anderen Port als Endpunkt der Verbindung.
TCP ist also eine gute Grundlage für Anwendungen, welche eine verlässliche Kommunikation erfordern.
Hypertext Transfer Protocol
Auch HTTP, das Protokoll, über welches beispielsweise ein Browser als Client mit einem Webserver bei Webseiten oder Webformularen Daten als HTTP Requests verschickt und als HTTP Reponse zurückkommen, setzt wiederum in einer weiteren Schicht auf TCP auf.
Dadurch, dass TCP die Reihenfolge aller verschickten Datenpakete letztendlich sicherstellen kann, ist überhaupt erst garantiert, dass mitunter Formulardaten in der selben Reihenfolge ankommen in welcher diese verschickt werden.
File Transfer Protocol
Eine Vielzahl von Dateien wird zwischen zwei Rechnern zum Server über FTP verschickt beziehungsweise SFTP für die gesicherte Verbindung.
Auch bei FTP ist es von Bedeutung, dass die Kommunikation auch über die Kommunikationskanäle weiterhin in der selben Reihenfolge ankommt wie diese verschickt wurde.
UDP
User Datagram
User Datagramme sind mitunter bekannt durch den ping
Befehl.
Was man im Mindestumfang wissen sollte:
Das User Datagram Protocol
UDP unterscheidet sich von TCP maßgeblich darin, dass bei UDP der Empfang von Datagrammen und damit Datenpaketen NICHT garantiert wird.
Datagramme
Die Datenpakete, die via UDP verschickt werden, bezeichnet man als Datagramme, engl. Datagram(s).
Man kann Sie vom Prinzip her mit einem «Brief» im herkömmlichen Postversand vergleichen. Man definiert ein Ziel, schickt die Daten ab, und das war's.
UDP unterscheidet sich von TCP maßgeblich darin, dass bei UDP der Empfang von Datagrammen und damit Datenpaketen NICHT garantiert wird.
Ohne Garantie der Reihenfolge
Die verschickten Datagramme bei UDP werden in der einen Reihenfolge verschickt, könnten aber in einer völlig anderen Reihenfolge unabhängig voneinander ankommen.
Unabhängigkeit von Paketen
Während bei TCP die Verbindung zwischen Sender und Empfänger erhalten wird, ist es bei UDP anders.
Die Daten werden nur verschickt. Auf eine Antwort wird gar nicht gewartet.
UDP: viele Pakete senden und mit Verlusten leben
Bei UDP basiert das Prinzip wie beispielsweise bei einem PING eines anderen Rechners darin, dass lieber mehrere Datenpakete als Datagramme sendet, den Verlust von Paketen aber akzeptiert.
Wenn also nur darum geht, um prüfen zu können, ob ein anderer Rechner überhaupt noch verfügbar ist oder man quasi einen Status herumschickt, ohne dass es einen interessiert, ob das nun jeder gerade bekommen hat, ist UDP denkbar.
UDP wird in vielen Firewalls inzwischen konsequent geblockt, dh. Firewalls können zwischen TCP und UDP Paketen differenzieren. TCP ist unerlässlich beim Aufbauen von Verbindungen. Da man die Daten, die man per UDP verschickt, auch in TCP hätte verpacken können, ist das für Entwickler einer Anwendung auch kein großes Problem.
Gaming: Im Spielebereich macht z. T. UDP wieder einen Sinn, so dass man ggf. mal die Firewall konfigurieren muss.
IP und Port
Authority-Parameter von URIs und URLs
Im Regelfall hat jeder Rechner nur eine Verbindung mit dem Netzwerk, dh. alles, was man versenden oder empfangen muss, muss letztendlich hier vermittelt werden. Damit man bei jedem Datenpaket wissen kann, zu welcher Programmanwendung es eigentlich gehört, hat man die sogenannten Ports als Anfangs- und Endpunkt einer Verbindung geschaffen.
URIs und URLs in Java kombinieren das wahlweise als uri.getAuthority()-Parameter
oder auch separat als uri.getHost() und
uri.getPort().
InetSocketAddress addr = new InetSocketAddress(host, port):
Die Kombination von IP-Adresse und Port findet sich mitunter in der Definition
von Internet-Socket-Adressen in Java, wobei der host die IP-Adresse enthalten kann,
wobei dort zumeist eine Domain steht.
Was man im Mindestumfang wissen sollte:
localhost:6000, 127.0.0.1:6000, example.com
Um über Netzwerkverbindungen Daten von einer Anwendung des einen Rechners an eine andere Anwendung auf dem selben oder einen anderen Rechner verschicken zu können, muss man primär zwei Dinge kennen:
Man benötigt die IP-Adressen oder aber zumindest die Domain. Die lokale IP-Adresse eines Rechners, auch als Loopback-Adapter bezeichnet, lautet als Domain localhost und als IP-Adresse im IPv4 Format dann 127.0.0.1.
Gefolgt nach einem : folgt dann
der zugehörige Port wie beispielsweise Port 6000
Computer werden über 32-bit-IP-Adressen addressiert
Das entspricht 2 hoch 32 Adressen abzüglich derer, die aus anderen Gründen gesperrt sind wie mitunter die 127.0.0.1.
Die Anzahl von Ports wird über 16-bit beschränkt
Die maximale Anzahl von Ports auf einem Rechner bzw. seiner Netzwerkkarte liegt also bei 2 hoch 16 Ports, damit via TCP oder IP eine Verbindung aufgenommen werden kann.
Reservieren von Ports
Um eine TCP Verbindung, engl. Connection, aufbauen zu können, verbindet sich eine Programmanwendung auf dem Server über einen Socket auf einem bestimmten Port.
Normalerweise ist es nun so, dass nur dieses eine Programm diesen Port reserviert hat und damit jedes andere Programm, welches als dann «Client» mit diesem «Server» auf diesem Port Kontakt aufnimmt, die Daten auch genau über diesen Socket an dieses eine Programm sendet.
Wichtige Standardports sollten vermieden werden.
Eine Reihe von Ports zwischen 0 und 1023 sind weltweit für bestimmte Protokolle wie beispielweise Port 80 für HTTP, Port 443 für HTTS und dergleichen beschränkt.
Es ist zwar technisch zuweilen möglich, dass Ihr Programm diese Ports dennoch verwendet und damit zweckentwendet, aber das Risiko, dass hierbei Probleme entstehen werden, ist doch höher.
Man muss hierzu nun noch wissen, dass Firewalls üblicherweise den Netzwerkverkehr nur für bestimmte Ports und Typen von Datenpaketen zulassen.
Domainnamen lassen sich mit IP-Adressen verbinden
Domainnamen dienen primär dem Zweck, damit man Rechner oder Services darauf immer mit der gleichen Adresse und damit dem URL Objekt adressieren kann, auch dann, wenn sich mal die IP-Adresse verändert.
Wenn ein Programm den Rechner nicht finden kann.
Um die Namensauflösung von Domainnamen wie
example.com oder
auch localhost
oder
wasauchimmer
kümmern sich mitunter Administratoren im Netzwerk oder
rund um die Thematik des Webhostings, doch es gibt Ausnahmen:
So können oder auch müssen für Anwendungen auf dem eigenen Rechner zuweilen virtuelle Hosts eingetragen werden, so dass man beispielsweise auch eine im Internet schon belegte Domain auch lokal angelegen kann, so dass Zugriffe auf diese Domain nicht mehr für den Zugriff ins Internet erfolgen sondern auf eine lokale Ressource.
DNS
Namensauflösung und DNS
Um von einem Domainnamen auf eine IP-Adresse schließen können, muss der zugehörige Domainname der Name aufgelöst werden.
Diese Auflösung des host-Namen in einem URI oder einem URI hat mit Java Programmierung nur am Rande zu tun, denn die Namensauflösung erfolgt über mehrere Schritte.
Was man im Mindestumfang wissen sollte:
Domain-Name / Hostname
Ein Domain-Name oder Hostname ist ein menschenlesbarer Alias, unter dem ein Rechner im Netz erreichbar ist (z. B. example.com statt 93.184.216.34).
In Java kann man ihn mit
InetAddress.getHostName() erfragen.
DNS (Domain Name System)
DNS ist das verteilte System, das Hostnamen in IP-Adressen (und umgekehrt) übersetzt. Java nutzt intern das Betriebssystem oder native Libraries (über JNI) für die DNS-Auflösung, kann aber kein eigenes DNS-Protokoll „out of the box“ implementieren.
A- und AAAA-Records
Ein A-Record verknüpft einen Hostnamen mit einer IPv4-Adresse, ein AAAA-Record mit einer IPv6-Adresse. Die Time-to-Live-Angabe (TTL) legt fest, wie lange diese Information im Cache bleibt.
CNAME-Record
Ein CNAME (Canonical Name) definiert einen Alias für einen anderen Hostnamen. DNS-Server leiten bei der Auflösung automatisch auf den kanonischen Namen weiter.
Reverse DNS / PTR-Record
Ein PTR-Record verbindet eine IP-Adresse mit einem Hostnamen (umgekehrte Auflösung), z. B. für E-Mail-Server.
In Java kann man ihn mit
InetAddress.getHostName() erfragen.
TTL (Time to Live)
Die TTL-Angabe in einem DNS-Record steuert, wie lange Ergebnisse im Cache gespeichert bleiben. Kurze TTLs führen zu häufigeren DNS-Anfragen, lange TTLs reduzieren die Last auf den Nameservern.
Domain-Name / Hostname
In Produktivumgebungen hängt der Hostname an richtigen DNS-Records. Bei einer lokalen Umgebung muss man unter Windows aber ggf. die WIndows-Hosts-Datei editieren:
File: \Windows\System32\drivers\etc\hosts
Dort lässt sich
example.local 127.0.0.1
auf
127.0.0.1
mappen.
Standard-Windows-Firewall blockiert eingehende TCP-Verbindungen.
Um überhaupt auf einem PC von einem anderen PC im lokalen Netzwerk Verbindungen annehmen zu können, müssen für HTTP und HTTPS die Ports 80 und 443 geöffnet werden.
netsh advfirewall firewall add rule name="HTTP" dir=in action=allow protocol=TCP localport=80
all add rule name="HTTPS" dir=in action=allow protocol=TCP localport=443
Für nicht-privilegierte Ports mit einer Portnummer größer oder gleich 1024 sind KEINE Admin-Rechte erforderlich. In den anderen Fällen muss man Dienste als Admin starten oder die URL eines Service mit HTTP.SYS reserverieren.
Für Java-Anwendungen wie Servlets und JSP hat man einst früher den Port
8080 verwendet; dieser liegt über 1024.
com.sun.net.httpserver.HttpServer und HttpListener
Um mit Java mit HttpListener auf einem Port lauschen zu können oder aber den mit Java ausgelieferten eigenen HttpServer verwenden zu können, muss man sicherstellen, dass Windows einem die Reservierung über HTTP.SYS-URLs ermöglicht.
netsh http add urlacl url=http://+:8080/ user="DOMAIN\benutzer" listen=yes
com.sun.net.httpserver.HttpServer wird mit Java
ausgeliefert und darf als Grundlage für eigene Webanwendungen verwendet werden,
auch wenn com.sun.net als Package-Name den Eindruck erweckt, dass es ggf.
geschützt sein könnte.
Wenn der Datenverkehr über Proxies läuft
In Fällen, in welchen der Datenverkehr nicht direkt sondern über Proxies läuft, benötigt man einen Reverse-Proxy.
Unter Windows kann man mitunter den IIS Internet Information Server mit einem speziellen Modul verwenden. Im Internet nutzt man für Webhosting von Webseiten und Webservices aber zumeist Nginx.
Wie man Nginx unter Windows oder Linux konfiguriert, ist nicht Inhalt dieser Einführung.
Das Binding eines Webservices an IPs und Domains
Header X-Forwarded-For, X-Forwared-Host, X-Forwared-Proto
Network Address Translation
Wenn man sich in einem Firmennetz oder Heimnetz beispielsweise hinter einem DSL-Router, den viele Menschen inzwischen nur noch als FritzBox kennen, oder einem anderen Router befindet, müssen die Adressen und Ports, die von außen adressiert wurden, auf die eigentlichen IPs und Ports innerhalb des über den Router abgesicherten Netzwerks «übersetzt» werden. Das bezeichnet man als Network Address Translation, kurz NAT.
Warum ein Proxy vor eurem ServerSocket?
Ein Reverse-Proxy läuft als eigener Dienst zwischen Router und eurer Java-App. Er terminiert TLS, verteilt Last (Load-Balancing), cached Inhalte und schützt die Backends.
Technisch empfängt NGINX die HTTP-Anfrage, liest Host-Header und Pfad und leitet sie per TCP oder HTTP an den internen ServerSocket weiter (z.B. localhost:8080).
Eure Java-App sieht nur eine „lokale“ Verbindung – um dennoch den echten Client zu erkennen, setzt der Proxy Header:
// in Java (Sun HTTP-Server oder Servlet-API) String clientIp = exchange.getRequestHeaders() .getFirst("X-Forwarded-For"); String scheme = exchange.getRequestHeaders() .getFirst("X-Forwarded-Proto");
So könnt ihr in Logs, URLs oder Sicherheitsregeln den ursprünglichen Client-IP, das Host-Mapping und Protokoll korrekt abrufen.
Das Binding eines ServerSockets
Binding reserviert einen Port und eine lokale Adresse, auf der euer ServerSocket lauscht. Ohne explizites Binding nutzt Java die Wildcard-Adresse (0.0.0.0) und einen dynamischen Port.
Bindet ihr z. B. an 127.0.0.1, sind nur lokale Clients zugelassen. Für alle Interfaces wählt 0.0.0.0.
// bindet auf Port 8080 für alle Interfaces ServerSocket server = new ServerSocket(8080, 50, InetAddress.getByName("0.0.0.0"));
Was NAT leistet (und was nicht)
NAT übersetzt IP-Adressen und Ports auf OSI-Schicht 3/4: Externe Anfragen an eure öffentliche IP werden im Router auf die private IP/den Port eures Servers weitergeleitet.
Anders als ein Proxy ändert NAT nicht den HTTP-Header oder Inhalt – es manipuliert nur IP- und TCP/UDP-Felder. Eure Java-App ist sich dessen nicht bewusst und erhält eine “normale” Verbindung.
Java Klassen für Netzwerkverbindungen
Es gibt eine Reihe von Klassen in Java, die jeder Entwickler schon mal gehört haben sollte, wenn es um die Thematik einer Kommunikation über Netzwerk- oder Internetverbindungen geht.
Was man im Mindestumfang wissen sollte:
java.net ermöglicht UDP/TCP Verbindungen im Netzwerk
Uniform Ressource Locator oder aber Java Klasse
Der URL Uniform Ressource Locator umfasst alle Informationen zu einer Zieladresse mit Protokoll, IP-Adresse, Port, URI und damit zuweilen im Falle von HTTP auch GET-Parametern.
In JAVA steht URL zuerst einmal für die Klasse und damit den Typ von Objekten.
localhost:6000 ist also
eine Adresse auf einem Server ohne Angabe des Protokolls, während
hingegen http://localhost:8080
die Domain und damit via Namensauflösung die IP-Adresse
mit dem Port adressiert, hierbei die Daten aber dann
im HTTP Protokoll verpacken will.
http:// bezeichnet man als Bezeichner für das Protokoll, englisch «protocol identifier».
localhost bezeichnet man hierbei als Name der Ressource, auch oft als Hostname bezeichnet.
Mit #sprungmarke kann mitunter
zuweilen noch ein benannter Anchor beispielsweise bei HTTP
angegeben werden, so dass nicht nur ein File-Name adressiert
werden kann sondern auch die Sprungmarke in einem HTML
Dokument.
Ein- und Ausgehende Verbindungen
Ein Socket auf einem Port für eine IP-Adresse stellt sicher, dass eingehende Verbindungen vom ServerSocket akzeptiert werden können, für die weitere Verbindung aber dann ein neuer Socket erzeugt wird, über welchen die eigentliche Kommunikation mit dem Client dann fortgesetzt wird.
Links
Quellen, Notes, Tags
UIO3 Es ist einfacher als Du denkst.
Stelle noch heute Deine Anfrage.
