vs Kommunikationsdienste des Betriebssystems Interprozesskommunikation (inter-process communication, IPC) am Beispiel Unix HW BS Prozesse Kommunizierende Threads Kommunizierende Prozesse Netzkommunikat ion Threads
vs2.4 2 Interprozesskommunikation ist sprachunabhängig: - Nachrichten sind ungetypt, d.h. Bytes oder Byte-Folgen, - rohe Semantik ohne syntaktischen Zucker, - u.U. verschiedene Semantiken zur Auswahl. Pipes, Named Pipes, Message Queues,... für lokale IPC Sockets für netzweite IPC
vs Pipes Pipe = Simplex-Kanal (BSD: Duplex!) verbunden mit einem Eingabe- und einem Ausgabe-Port (typischerweise verschiedener Prozesse) Senden: int write(int port, char *buffer, int length) Empfangen: int read(int port, char *buffer, int length) Adressierung:portbezogen Konfigurierung:dynamisch durch Programm: Erzeugung von Prozessen und Pipes, Vererben von Ports bei Prozesserzeugung Semantik:zuverlässiger Byte-Strom mit begrenzter Pufferung; read erfolgreich, sobald mindestens 1 Byte vorliegt; write erfolgreich, sobald length Bytes frei; auch nichtblockierende Versionen.
vs2.4 4 int n; int piped[2]; char buf[11]; pipe( piped ); /* pipe erzeugen */ /* 0=Leseport, 1=Schreibport */ if ( fork() ) {/* Kindprozess erzeugen */ close( piped[0] ); /* Eltern lesen nicht */ printf("Eltern: Schreiben an Kind.\n"); write( piped[1], "hallo Kind", 11 ) ; } else { close( piped[1] ); /* Kind schreibt nichts */ printf("Kind: Lesen von Eltern.\n"); n = read( piped[0], buf, 11 ); printf("Kind: %d Zeichen gelesen: %s.\n", n, buf ); }
vs Sockets (socket = Steckdose) Socket = Duplex-Port (Senden und Empfangen) für lokale und netzweite IPC mit unterschiedlich wählbaren Semantiken Adressierung:portbezogen Konfigurierung:dynamisch durch Programm: Erzeugung lokaler Sockets, Binden an Sockets anderer Prozesse Semantik:zuverlässiger Byte-Strom oder Einzelnachrichten ohne Reihenfolge- garantie oder Schutz gegen Verlust
vs2.4 6 Erzeugen eines – ungebundenen – Socket: int socket(int family, int type, int protocol) prozeßlokaleProtokoll-Transport-Protokoll Port-NummerFamilieDienst(i.d.R. 0 [Null]) IP SOCK_RAW IDPUDP SOCK_DGRAM SPPTCP SOCK_STREAM PF_NS PF_INET PF_UNIX Familie Dienst Wählbare Varianten ≈ Semantik
vs2.4 7 Neu erzeugte Socket ist noch nicht anspechbar! Muss zunächst mit netzweit gültiger Adresse benannt (gebunden) werden: int bind(int socket, struct sockaddr *address, int addrlen) (Protokollfamilie, stationslokale Port-Nummer, Stationsadresse) z.B. PF_INET, a-16-bitPortNumber, a-32-bitHostAddress Prozess 7 80 socket Kommunikationspartner Host
vs2.4 8 Dienst SOCK_DGRAM für Internet: verbindungslose, unzuverlässige Nachrichtenübertragung mit UDP Abstrakt: send MsgExpr to ProcExpr int sendto(int socket, char *buffer, int length, int flags, struct sockaddr *to, int addrlen) Absender socket sendet an Adressat to Abstrakt: recv MsgVar from ProcVar int recvfrom(int socket, char *buffer, int length, int flags, struct sockaddr *from, int *addrlen) socket empfängt an ihn gesendete Nachricht sowie Absender
vs2.4 9 Dienst SOCK_STREAM für Internet: verbindungsorientiert - zuverlässiger Byte-Strom mit TCP Konfigurierung ist an Szenario Auftraggeber/Auftragnehmer orientiert: Initiative geht von einem Klienten aus ! Nach erfolgreich hergestellter Verbindung Nachrichtenaustausch mittels (Klient)(Server) write(s1,request,length); read(s3,request,length);... write(s3,reply,length); read(s1,reply,length);
vs Herstellung der Verbindung: (Klient)(Server) s1 = socket(...);s2 = socket(...); [ bind(s1,..); ] bind(s2,&local,l); listen(s2, qlength); connect(s1,&dest,l);s3 = accept(s2,&source,&l); write(s1,...);read(s3,...);... close(s1);close(s3); Server-Socket s2 nimmt nur Verbindung entgegen! Kommunikation über neu erzeugte Socket s3. Konfiguration Kommunikation
vs Java unterstützt das Arbeiten mit Sockets durch Bibliotheksklassen Socket, ServerSocket, DatagramSocket, MulticastSocket,..... siehe java.net.*
vs Klient: byte[] buf =...; InetAddress oder String (Name) Socket s1 = new Socket(dstHost, dstPort); InputStream in = s1.getInputStream(); OutputStream out = s1.getOutputStream(); out.write(buf); int n = in.read(buf); Server: ServerSocket s2 = new ServerSocket(localPort); Socket s3 = s2.accept(); srcHost = s3.getInetAddress(); srcPort = s3.getPort(); InputStream in = s3.getInputStream(); OutputStream out = s3.getOutputStream(); int n = in.read(buf); out.write(buf);
vs Gruppenkommunikations (Multicast): UDP-basiert (verbindungslos, unzuverlässig) Unterscheidung von "normalen" UDP-Sockets durch speziellen Multicast-Adressbereich ( ) Verwendung z.B. mit java.net.MulticastSocket: public class MulticastSocket extends DatagramSocket {... public void joinGroup(InetAddress mcast) {... } public void leaveGroup(InetAddress mcast) {... }... }
vs InetAddress mcast = InetAddress.getByName(" "); DatagramSocket s = new MulticastSocket(8711); s.joinGroup(mcast); DatagramPacket msg = DatagramPacket(buf, len, group, 8711); s.send(msg); s.receive(new DatagramPacket(buf, len)); Gruppenteilname ist nur für Empfang (blau) erforderlich. Versand ist auch möglich, ohne der Gruppe anzugehören.
vs Nichtsequentielle Server Beachte: Server operiert in nichtsequentieller Umgebung Verbindungsbearbeitung/ Auftragsbearbeitung sequentiell, exklusiv (Server Monitor!) nichtsequentiell, überlappend je Verbindung ein Prozessein Thread
vs Server kann auch mehrere Dienste anbieten, z.B. für jeden Dienst ein eigener Port ! Realisierung: a) sequentiell: disjunktives Warten auf Verbindungswünsche über alle angebotenen Ports b) nichtsequentiell: je Port ein (statischer) Thread, darin sequentielle Bearbeitung c) nichtsequentiell: disjunktives Warten + (dynamische) Threads, ein Thread (aus Pool) pro Verbindung d) nichtsequentiell: disjunktives Warten + Prozesse, neu erzeugter Prozess pro Verbindung
vs Realisierung disjunktiven Wartens Warten auf Verbindungsanforderungen über mehrere Sockets - allgemein: auf Empfangs/Sende-Möglichkeit über Kanäle - innerhalb eines sequentiellen Programms Alternativen: wiederholtes nichtblockierendes Senden/Empfangen („polling“) nichtblockierendes Senden/Empfangen mit Signalisierung durch Software-Unterbrechung (Unix: signal SIGIO ) - mühsam ! disjunktives Warten mit Systemaufruf (Unix:) select
vs int fd1 =..., fd2 =...; fd_set rfds; // Bit-Liste int maxfd = max(fd1,fd2)+1; // Länge der Bit-Liste struct timeval timeout; for (;;) { // registrieren FD_ZERO(&rfds); FD_SET(fd1, &rfds);// Bitlisten-Operationen FD_SET(fd2, &rfds); timeout.tv_sec = 5; timeout.tv_usec = 0; // Bit-Listen prüfen auf: read/ write/ except // accept connect int ready = select(maxfd, &rfds, NULL, NULL, &timeout); // auswerten if (ready == 0)... timeout behandeln... continue; if (FD_ISSET(fd1, &rfds))... fd1 auslesen if (FD_ISSET(fd2, &rfds))... fd2 auslesen }
vs In Java unterstützt durch java.nio.* (“new I/O”) Pakete SocketChannel sc1=..., sc2=...; // Selector erzeugen und Kanäle registieren Selector selector = Selector.open(); sc1.register(selector, SelectionKey.OP_READ); sc2.register(selector, SelectionKey.OP_READ); // oder OP_ACCEPT, OP_CONNECT, OP_WRITE while (true) { int ready = selector.select(5000); if (ready == 0) continue; //...Timeout behandeln... Set selectedKeys = selector.selectedKeys(); Iterator it = selectedKeys.iterator(); while (it.hasNext()) { SelectionKey key = (SelectionKey) it.next(); if ((key.readyOps() & SelectionKey.OP_READ) != 0) { SocketChannel sc = (SocketChannel)key.channel(); //...Daten von Kanal lesen... } it.remove(); }
vs Datenkonvertierung bei Hardware-Heterogenität Byte-Reihenfolge, z.B. für 16-Bit-Ganzzahlen: „little-endian“ (Intel,..) „big-endian“(Motorola,..) Zeichen: ASCII, EBCDIC, UTF-8/16,... Gleitkommazahlen: IEEE-Standard,... a+1 a a a+1
vs Alternativen: 1) Ad-hoc-Umwandlung, „receiver makes it right” 2) Verwendung einer kanonischen Darstellung auf dem Netz (external data representation) Auch Felder, Verbunde, Objekte,... behandeln ! Bezug zu:- Typsystem der Programmiersprache - vom Übersetzer gewählte interne Darstellung - evtl. Sprachheterogenität ! (Wir kommen in einem späteren Kapitel darauf zurück.) [ Zuständig gemäß OSI-Referenzmodell: Presentation Layer (6) ]
vs Für Internet-Kommunikation: Unterstützung durch Bibliotheksroutinen in C für Ganzzahlen: "machine byte order" "network byte order" u_long htonl(u_long number); „host to network long“ u_short htons(u_short number); u_long ntohl(u_long number); u_short ntohs(u_short number);
vs Java: automatische Umcodierung bei Benutzung von Socket- Objekten - siehe Dokumentation ! OutputStream os = mySocket.getOutputStream(); ObjectOutput out = new ObjectOutputStream(os); out.writeInt(i); out.writeFloat(f); out.writeBoolean(b);... out.writeObject(o); // o must be Serializable or... Entsprechend für Eingabe...