Netzprogrammierung: Kommunikation über Sockets Robert Tolksdorf und Peter Löhr Überblick • Internet-Dienste und -Protokolle • IP-Adressen und Rechnernamen • Portnummern • Kommunikation über Sockets • TCP • UDP • Multicast Robert Tolksdorf und Peter Löhr 2 Internet-Dienste und -Protokolle Robert Tolksdorf und Peter Löhr Was ist das Internet ? • (hardware-bezogene Sicht:) Ein weltweiter Verbund von Rechnern, die über Netze Daten austauschen können • Zusammenschalten von lokalen Netzen zum Internet • dabei notwendige Verarbeitung von Datenpaketen • (netzbezogene Sicht:) Eine Familie von Kommunikationsdiensten und -protokollen • Spezifikation von Kommunikationsdiensten • Spezifikation von Protokollen zur Dienst-Implementierung • (anwendungsbezogene Sicht:) Ein offenes System, in dem Anwendungsdienste angeboten und genutzt werden können Robert Tolksdorf und Peter Löhr 4 Vermittlungsdienst im Internet • Das Internet Protocol IP ermöglicht “internetworking” durch Etablierung von Datenformaten und Interaktionsregeln, die von unterschiedlichen Netztechnologien abstrahieren • IP erbringt Vermittlungsdienst: Übertragung von Datenpaketen von Quellrechner zu Zielrechner, ggfls. über Zwischenstationen x.inf.fu-berlin.de a.cs.tu-berlin.de y.inf.fu-berlin.de b.cs.tu-berlin.de z.inf.fu-berlin.de c.cs.tu-berlin.de Ethernet Robert Tolksdorf und Peter Löhr ATM 5 IP-Adressen • Identifizierung eines Rechners im Netz durch IP-Adresse, auch Internet-Adresse • aktuell 32 Bit, notiert als 4 Bytes in Dezimaldarstellung, z.B. 130.149.27.12 • IP-Adresse ist per Software festgelegt (wird im Lokalnetz auf eine physikalische Netzadresse abgebildet, die MAC-Adresse [media access control] ) • Routing-Funktionalität des IP-Protokolls besorgt das Weiterleiten von Paketen über Zwischenstationen zur endgültigen Zielstation (mit Hilfe von routing tables) Robert Tolksdorf und Peter Löhr 6 Rechnernamen und DNS • mnemonische Identifizierung von Rechnern durch Namen, z.B. bobspc, nawab, troll (im lokalen Netz) • Weltweit hierarchischer Namensraum: Domain Name System (DNS) mit Namen wie • troll.mi.fu-berlin.de für den Rechner 160.45.45.50 • Domain Name Service (DNS) ist zuständig für die Zuordnung zwischen Namen und Adressen (Empfehlung: http://ping.eu) Robert Tolksdorf und Peter Löhr 7 Systemfunktionen #include <netdb.h> struct hostent *gethostbyname(char *hostname) liefert den Verweis auf einen Verbund, der u.a. die IP-Adresse(n) des genannten Rechners enthält struct hostent *gethostbyaddr (char *addr, int len, int type) arbeitet umgekehrt (Implementierung: DNS befragen - oder /etc/hosts oder ...) #include <netinet/in.h> unsigned long inet_addr(char *ptr) wandelt eine IP-Adresse in die 32-Bit-Darstellung char *inet_ntoa(struct in_addr addr) arbeitet umgekehrt Robert Tolksdorf und Peter Löhr 8 ... und mit java.net.InetAddress • Klasse InetAddress für Adress-Objekte: • byte[] getAddress() liefert IP-Adresse als 4-Byte-Feld, z.B. {10,1,2,12} (network byte order: big-endian!) • String getHostAddress() … als Zeichenkette in Punktnotation, z.B. “10.1.2.12“ • String getHostName() liefert den Namen Robert Tolksdorf und Peter Löhr 9 ... und mit java.net.InetAddress • Erzeugung von Adress-Objekten: • static InetAddress getByName(String host) Beispiele: w3c = InetAddress.getByName(“www.w3c.org”); mypc = InetAddress.getByName(“localhost”); (“loopback interface”) nix = InetAddress.getByName(“10.1.2.12”);(!) • static InetAddress getByAddress(byte[] addr) Beispiel: myserver = InetAddress.getByAddress(new byte[] {10,1,2,12}); • static InetAddress getLocalHost() liefert Adress-Objekt, mit dem der lokale Rechner von außen erreicht werden kann. Gewöhnlich gilt also nicht InetAddress.getLocalHost().equals( InetAddress.getByName(“localhost“)) sondern: Robert Tolksdorf und Peter Löhr 10 System.out.println(InetAddress.getByName("localhost")); produziert localhost/127.0.0.1 System.out.println(InetAddress.getLocalHost()); produziert imp048229.vpn.mi.fu-berlin.de/10.1.246.230 (oder ähnlich) Robert Tolksdorf und Peter Löhr 11 Beispiel • Namen umwandeln in Punktnotation: import java.net.*; class IP { public static void main(String[] args) throws Exception { InetAddress addr = InetAddress.getByName(args[0]); System.out.println(addr.getHostAddress()); } } $ java IP troll.mi.fu-berlin.de 160.45.45.50 $ Robert Tolksdorf und Peter Löhr 12 Transportdienste • Transportdienst besorgt den Transport von Daten zwischen Kommunikationsendpunkten (= virtuelle Netzanschlüsse), die von Prozessen verwendet werden. • Die Implementierung orientiert sich an der Spezifikation zugehöriger Transportprotokolle und benutzt den IP-Dienst • Zwei typische Transportdienste im Internet: • UDP (user datagram protocol) unterscheidet sich nur unwesentlich vom IP-Dienst: eine Nachricht wird als Datagramm auf den Weg durchs Netz geschickt, ohne dass das Eintreffen am Zielendpunkt garantiert wird (verbindungsloser Dienst). • TCP (transmission control protocol) etabliert einen zuverlässigen Byte-Strom zwischen Quelle und Ziel, die zu diesem Zweck eine virtuelle Verbindung herstellen (verbindungsorientierter Dienst) Robert Tolksdorf und Peter Löhr 13 Ports und Sockets • Ein Port ist eine Nummer im Bereich [0..65535] zur Identifizierung von Anbietern von Anwendungsdiensten und deren Klienten (synonym auch Portnummer). Der Bereich [0..1023] ist für Standarddienste reserviert. • Ein Socket (dt. Steckdose) ist ein mit einer Portnummer versehener Kommunikationsendpunkt auf Anbieterseite oder Klientenseite. Im Fall einer TCP-Verbindung besteht eine Assoziation eines anbieterseitigen Sockets mit einem klientenseitigen Socket. Robert Tolksdorf und Peter Löhr 14 TCP Transmission Control Protocol Robert Tolksdorf und Peter Löhr TCP Sockets • Erzeugung eines Socket: #include <sys/socket.h> int socket(int family, int type, int protocol) prozesslokale SocketNummer ProtokollFamilie: AF_INET Dienst: TCP Protokoll: 0 • Netzweit gültige Benennung eines Socket durch einen Anbieter - mit Reservierung eines freien Ports: int bind(int socket, struct sockaddr *address, wählt Portnummer int addrlen) und IP-Adresse Robert Tolksdorf und Peter Löhr 16 TCP Sockets • Festlegung der akzeptierten Warteschlangenlänge: int listen(int socket, int backlog) • Annahme des Verbindungswunschs eines Klienten: int accept(int socket, struct sockaddr *client, int *addrlen) Nummer eines neugeschaffenen (!) Socket, der mit dem Socket des Klienten verbunden ist. Damit ist zwischen beiden Sockets ein bidirektionaler Kommunikationskanal eingerichtet. Beachte: der neue Socket trägt die gleiche Portnummer wie der alte; wegen seiner Assoziation mit dem Port des Klienten stellt er dennoch einen neuen Kommunikationsendpunkt dar. Robert Tolksdorf und Peter Löhr 17 TCP Sockets • Was tut der Klient? • Socket erzeugen: wie auf S. 16 • (wahlweise:) Socket benennen: wie auf S. 16; falls die Benennung unterbleibt, wählt das System im nächsten Schritt irgendeine freie Portnummer. • Verbindungswunsch an den Server richten: #include <sys/socket.h> int connect(int socket, struct sockaddr *server, int addrlen) • Nach Rückkehr von connect Benutzung der Verbindung auf • beiden Seiten mit read/write auf den jeweiligen Sockets Abbau der Verbindung mit int close(int socket) (einseitig oder beidseitig) Robert Tolksdorf und Peter Löhr 18 TCP Sockets 1. Anbieter reserviert Port bind 2. Anbieter macht sich bereit 3. Anbieter wartet auf Verbindungswunsch, Klient schickt Verbindungswunsch 4. Klient und Anbieter sind verbunden - bidirektional! 5. Verbindung wird abgebaut Robert Tolksdorf und Peter Löhr listen connect accept read/write read/write close close 19 TCP Sockets Klienten 47111 Server 12345 12346 22 22 22 22 22 43210 ( Port 22: Dienst ssh ) Robert Tolksdorf und Peter Löhr 20 TCP Sockets • ... und nicht vergessen: eventuell unterschiedliche Datenrepräsentation in beiden Rechnern! Das kann selbst dann fatal sein, wenn nur Zeichen übertragen werden (Byte-Ordnung)! • Typische Hilfsfunktionen dafür: byte ordering routines #include <netinet/in.h> u_long htonl(u_long hostlong) u_short htons(u_short hostshort) u_long ntohl(u_long netlong) u_short ntohs(u_short netshort) Robert Tolksdorf und Peter Löhr 21 TCP Sockets • Klient "netcat" stellt Verbindung mit einem Dienstanbieter her und erlaubt Interaktion über Tastatur/Bildschirm: $ nc localhost 79 (Port 79: Dienst finger) lohr Login: lohr Name: Peter Löhr Directory: /Users/lohr Shell: /bin/bash On since Wed Oct 1 09:14 (CEST) on console, idle 17 days 8:46 (messa On since Fri Oct 17 15:20 (CEST) on ttyp1 No Mail. No Plan. $ $ nc nawab.mi.fu-berlin.de 13 (Port 13: Dienst daytime) Sat Oct 18 18:13:11 2008 $ Robert Tolksdorf und Peter Löhr 22 Socket-Objekte in Java • Paket java.net stellt geeignete public Klassen bereit: • abstract class SocketAddress { ... // Socket-Namen } • class InetSocketAddress extends SocketAddress { // Socket-Namen für Internet-Dienste, // bestehend aus IP-Adresse und Portnummer public InetSocketAddress(String hostname, int port) ... } Robert Tolksdorf und Peter Löhr 23 Socket-Objekte in Java • class Socket { // Klienten-Sockets public Socket() ...// unbenannte, unverbundene Sockets public Socket(String host, int port) throws ... // verbundene Sockets - mit port auf host public void bind(SocketAddress bindpoint) throws ... // benennt den Socket mit bindpoint public void connect(SocketAddress endpoint) throws ... // verbindet den Socket mit einem Anbieter// Socket mit dem Namen endpoint public void close() throws ... // macht den Socket unbenutzbar und trennt // eine eventuell existierende Verbindung public OutputStream getOutputStream() throws ... public InputStream getInputStream() throws ... // Senden und Empfangen von Bytes } Robert Tolksdorf und Peter Löhr 24 Socket-Objekte in Java • class ServerSocket { // Anbieter-Sockets public ServerSocket() throws ... // unbenannte, unverbundene Sockets public ServerSocket(int port, int backlog) throws ... // benannte, empfangsbereite Sockets public void bind(SocketAddress endpoint, int backlog) throws ... // benennt den Socket public Socket accept() throws ... // liefert einen neuen Socket, der mit dem // Socket eines Klienten verbunden ist public void close() throws ... // macht den Socket unbenutzbar und trennt // eine eventuell existierende Verbindung } Robert Tolksdorf und Peter Löhr 25 Beispiel Echo-Dienst • Ein Echo-Dienst: Anbieter wartet auf Zeichenketten und antwortet mit ähnlichen Zeichenketten • Starten des Dienstes: • Testen des Dienstes: mypc: nc nawab 12345 ping pong risibisi rosoboso ^C punt! mypc: Robert Tolksdorf und Peter Löhr nawab: java Echo 12345 & [1] 2011 nawab: mit eigenem Klienten: mypc: java Client nawab 12345 ping pong risibisi rosoboso ^D mypc: 26 Beispiel Echo-Dienst import java.io.*; import java.net.*; public class Echo { public static void main (String args[]) throws IOException { ServerSocket listen = new ServerSocket(Integer.parseInt(args[0])); while(true) { // non-terminating server Socket socket = listen.accept(); BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream())); PrintStream out = new PrintStream(socket.getOutputStream()); while (true) { // end of input stream will close dialogue String message = in.readLine(); if(message==null) break; String answer = message.replace('i','o'); out.println(answer); } in.close(); out.close(); socket.close(); // ready to accept new client } } } Robert Tolksdorf und Peter Löhr 27 Beispiel Echo-Dienst import java.io.*; import java.net.*; public class Client { public static void main (String args[]) throws IOException { Socket socket = new Socket(args[0], Integer.parseInt(args[1])); PrintStream out = new PrintStream(socket.getOutputStream()); BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); BufferedReader keyboard = new BufferedReader( new InputStreamReader(System.in)); while(true) { // ^D will close dialogue String message = keyboard.readLine(); if(message==null) break; out.println(message); String answer = in.readLine(); System.out.println(answer); } in.close(); out.close(); socket.close(); } } Robert Tolksdorf und Peter Löhr 28 Beachte: • Das Programm Client wickelt lediglich einen Dialog ab und weiß nichts von dem kontaktierten Dienst - insofern ähnelt es dem nc. Man probiere z.B. • java Client localhost 13 • nc localhost daytime • Der Dienst Echo ist insofern recht beschränkt, als er nicht mehrere Dialoge gleichzeitig führen kann. Wer den Dienst benutzen will, muss eventuell warten, bis ein gerade aktiver Benutzer seinen Dialog beendet. Robert Tolksdorf und Peter Löhr 29 UDP User Datagram Protocol Robert Tolksdorf und Peter Löhr TCP vs. UDP • TCP: Pakete werden geordnet und zuverlässig über eine Verbindung transportiert. Effekt: zuverlässiger, reihenfolgetreuer Byte-Strom. • UDP: Ein Paket („Datagramm“) wird auf den Weg von einem Socket zu einem anderen geschickt. Dass das Datagramm am Ziel eintrifft ist nicht garantiert, Reihenfolgetreue (FIFO) auch nicht. Robert Tolksdorf und Peter Löhr 31 UDP Sockets 1. Anbieter reserviert Port bind 2. Klient reserviert Port bind 3. Klient/Anbieter senden und empfangen Datagramme bidirektional! send receive 4. Ports und Sockets werden freigegeben close close Robert Tolksdorf und Peter Löhr 32 Beispiel Echo-Dienst • Variante des Echo-Dienstes von S. 25 - Starten: $ java EchoUDP 12345 & [1] 2011 $ • Testen des Dienstes: $ nc -u localhost 12345 ping pong singing songong ^C punt! $ Robert Tolksdorf und Peter Löhr (Option -u steht für UDP) 33 Beispiel Echo-Dienst import java.net.*; import java.io.*; public class EchoUDP { public static void main(String args[]) throws IOException { byte[] inData = new byte[1024]; byte[] outData = new byte[1024]; DatagramPacket in = new DatagramPacket(inData, inData.length); DatagramSocket socket = new DatagramSocket( Integer.parseInt(args[0])); while(true) { // non-terminating server socket.receive(in); // wait for message InetAddress senderAdress = in.getAddress(); int senderPort = in.getPort(); String message=new String(in.getData(), 0, in.getLength()); // build answer: Robert Tolksdorf und Peter Löhr 34 Beispiel Echo-Dienst outData = message.replace('i','o').getBytes(); DatagramPacket out = new DatagramPacket( outData, outData.length, senderAddress, senderPort); socket.send(out); // send answer } } } Beachte: Im Gegensatz zu TCP ist der empfangende Socket nicht mit dem sendenden Socket verbunden. Daher müssen die Absenderdaten senderAddress, senderPort für das richtige Adressieren der Antwort explizit gehandhabt werden. Robert Tolksdorf und Peter Löhr 35 ... und ein passender Klient import java.io.*; import java.net.*; public class ClientUDP { public static void main (String args[]) throws IOException { byte[] inData = new byte[1024]; byte[] outData = new byte[1024]; DatagramPacket in = new DatagramPacket(inData,inData.length); InetAddress server = InetAddress.getByName(args[0]); int port = Integer.parseInt(args[1]); DatagramSocket socket = new DatagramSocket(); // chooses some available local port BufferedReader keyboard = new BufferedReader( new InputStreamReader(System.in)); // dialogue starts here: Robert Tolksdorf und Peter Löhr 36 ... und ein passender Klient } } while(true) { // ^D will close dialogue String message = keyboard.readLine(); if(message==null) break; outData = message.getBytes(); DatagramPacket out = new DatagramPacket( outData, outData.length, server, port); socket.send(out); socket.receive(in); String answer = new String(in.getData(),0,in.getLength()); System.out.println(answer); } socket.close(); $ java ClientUDP localhost 12345 Robert Tolksdorf und Peter Löhr ping pong singing songong ^D $ 37