Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

 << zurück
Linux-UNIX-Programmierung von Jürgen Wolf
Das umfassende Handbuch – 2., aktualisierte und erweiterte Auflage 2006
Buch: Linux-UNIX-Programmierung

Linux-UNIX-Programmierung
1216 S., mit CD, 49,90 Euro
Rheinwerk Computing
ISBN 3-89842-749-8
gp Kapitel 11 Netzwerkprogrammierung
  gp 11.1 Einführung
  gp 11.2 Aufbau von Netzwerken
    gp 11.2.1 ISO/OSI und TCP/IP – Referenzmodell
    gp 11.2.2 Das World Wide Web (Internet)
  gp 11.3 TCP/IP – Aufbau und Struktur
    gp 11.3.1 Netzwerkschicht (Datenübertragung)
    gp 11.3.2 Internetschicht
    gp 11.3.3 Transportschicht (TCP, UDP)
    gp 11.3.4 Anwendungsschicht
  gp 11.4 TCP Socket
  gp 11.5 Kommunikationsmodell
  gp 11.6 Grundlegende Funktionen zum Zugriff auf die Socket-Schnittstelle
    gp 11.6.1 Ein Socket anlegen – socket()
    gp 11.6.2 Verbindungsaufbau – connect()
    gp 11.6.3 Socket mit einer Adresse verknüpfen – bind()
    gp 11.6.4 Auf Verbindungen warten – listen() und accept()
    gp 11.6.5 Senden und Empfangen von Daten (1) – write() und read()
    gp 11.6.6 Senden und Empfangen von Daten (2) – send() und recv()
    gp 11.6.7 Verbindung schließen – close()
  gp 11.7 Aufbau eines Clientprogramms
    gp 11.7.1 Zusammenfassung: Clientanwendung und Quellcode
  gp 11.8 Aufbau des Serverprogramms
    gp 11.8.1 Zusammenfassung: Serveranwendung und Quellcode
  gp 11.9 IP-Adressen konvertieren, manipulieren und extrahieren
    gp 11.9.1 inet_aton(), inet_pton() und inet_addr()
    gp 11.9.2 inet_ntoa() und inet_ntop()
    gp 11.9.3 inet_network()
    gp 11.9.4 inet_netof()
    gp 11.9.5 inet_lnaof()
    gp 11.9.6 inet_makeaddr()
  gp 11.10 Namen und IP-Adressen umwandeln
    gp 11.10.1 Name-Server
    gp 11.10.2 Informationen zum Rechner im Netz – gethostbyname und gethostbyaddr
    gp 11.10.3 Service-Informationen – getservbyname() und getservbyport()
  gp 11.11 Der Puffer
  gp 11.12 Standard-E/A-Funktionen verwenden
    gp 11.12.1 Pufferung von Standard-E/A-Funktionen
  gp 11.13 Parallele Server
  gp 11.14 Syncrones Multiplexing – select()
  gp 11.15 POSIX-Threads und Netzwerkprogrammierung
  gp 11.16 Optionen für Sockets setzen bzw. erfragen
    gp 11.16.1 setsockopt()
    gp 11.16.2 getsockopt()
    gp 11.16.3 Socket-Optionen
  gp 11.17 UDP
    gp 11.17.1 Clientanwendung
    gp 11.17.2 Serveranwendung
    gp 11.17.3 recvfrom() und sendto()
    gp 11.17.4 bind() verwenden oder weglassen
  gp 11.18 UNIX-Domain-Sockets (IPC)
    gp 11.18.1 Die Adressstruktur von UNIX-Domain-Sockets
    gp 11.18.2 Lokale Sockets erzeugen – socketpair()
  gp 11.19 Multicast-Socket
    gp 11.19.1 Anwendungsgebiete von Multicast-Verbindungen
  gp 11.20 Nicht blockierende I/O-Sockets
  gp 11.21 Etwas zu Streams und TLI, Raw Socket, XTI
    gp 11.21.1 Raw Socket
    gp 11.21.2 TLI und XTI
    gp 11.21.3 RPC (Remote Procedure Call)
  gp 11.22 IPv4 und IPv6
    gp 11.22.1 IPv6 – ein wenig genauer
  gp 11.23 Netzwerksoftware nach IPv6 portieren
    gp 11.23.1 Konstanten
    gp 11.23.2 Strukturen
    gp 11.23.3 Funktionen
  gp 11.24 Sicherheit und Verschlüsselung


Rheinwerk Computing

11.20 Nicht blockierende I/O-Sockets  toptop

Alle Socket-Beispiele, die Sie bisher kennen gelernt haben, haben die Ausführung des Programms blockiert (warten), wenn ein Socket-Aufruf seine Aktion nicht ausführen konnte. Das Blockieren von Sockets ist die Standardeinstellung – dies ist aber nicht unbedingt nötig. Sie können z. B. fcntl() verwenden, um einen Socket auf nicht blockierend zu setzen. Aber einen gravierenden Nachteil von nicht blockierenden Sockets gleich am Anfang: Das Programm befindet sich dadurch immer in einem dauerhaften Poll-Zustand, das heißt, es wird dauernd nach Daten am Socket überprüft, und das kostet CPU-Zeit, die bei einem Server kostbar ist. Nicht blockierende Sockets lassen sich in mehrere Kategorien einteilen:

gp  Eingehende Verbindungen mit accept() – Wird accept() für einen blockierenden Socket aufgerufen und es liegt keine Verbindung vor, wartet der Prozess so lange, bis eine Verbindung vorliegt. Das ist die Standardeinstellung. Wird accept() hingegen von einem nicht blockierenden Socket aufgerufen und es liegt keine Verbindung an, wird der Fehler EWOULDBLOCK (= EAGAIN) zurückgegeben. Entsprechend müssen Sie diese Fehlermeldung auch mit errno bearbeiten – sprich: abfangen.
gp  Ausgehende Verbindungen mit connect() – Richtet ein Client ein connect() an den Server (bei TCP) und es handelt sich um einen blockierenden Socket, so wartet connect() mindestens eine Zeitspanne von RTT (Round-Trip-Time) auf die Antwort vom Server. Wird connect() hingegen mit einem nicht blockierenden Socket aufgerufen und die Verbindung zur Gegenstelle wird nicht aufgebaut, liefert connect() den Fehler EINPROGRESS zurück. Auch diesen Fehler müssen Sie dann für den Fall der Fälle behandeln.
gp  Ein- und Ausgabeoperationen mit read(), recv(), recvfrom() bzw. write(), send(), sendto() – Bei Eingabeoperationen wird in der Standardeinstellung das Socket so lange blokkiert, bis Daten an diesem gelesen oder gesendet werden konnten. Bei TCP (als stream-orientierte Datenübertragung) wird die Blockierung nach Eintreffen von Daten aufgehoben. Bei UDP hingegen wird die Blockierung erst aufgehoben, wenn ein ganzes Paket (UDP-Datagramm) gesendet wird. Dies ist die Standardeinstellung. Werden Eingabeoperationen auf einem nicht blockierenden Socket ausgeführt, obwohl keine Eingaben vorhanden sind, wird der Fehler EWOULDBLOCK zurückgegeben. Bei den Ausgabeoperationen werden die Sockets blockiert, wenn für den Sendepuffer des blockierenden Sockets nicht genügend Platz reserviert wurden. Ist bei einem nicht blockierenden Socket nicht genügend Speicherplatz für den Sendepuffer vorhanden, wird EWOULDBLOCK zurückgegeben.

Im folgenden Beispiel sehen Sie eine einfache Möglichkeit von nicht blockierenden Sockets. Im Beispiel wird accept() eines TCP-Servers, der auf eine Verbindung eines Client wartet, auf nicht blockierend eingestellt. Nach jedem accept()-Aufruf fährt das Programm fort. In diesem Beispiel wird überprüft, ob accept() erfolgreich war oder nicht. Bei negativer Abfrage wird einfach die Meldung Poll: Kein Client am Socket ... jede Sekunde ausgegeben. Ebenso könnten Sie vorgehen, wenn Sie das zurückgegebene Socket von accept(), das anschließend für Lese- und Schreiboperationen verwendet wird, auf nicht blockierend setzen wollen – was im Beispiel in der do-while()-Schleife demonstriert wurde. Bei dem Listing handelt es sich allerdings nur um ein Grundgerüst, das aber den Sachverhalt der nicht blockierenden Ein-/Ausgabe von Sockets recht gut demonstriert.

/* non_block.c */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd. h.>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#define BUF 1024
int main (void) {
  int create_socket, new_socket, addrlen;
  char *buffer = malloc (BUF);
  struct sockaddr_in address;
  long save_fd;
  const int y = 1;
  printf ("\e[2J");
  if ((create_socket=socket( AF_INET, SOCK_STREAM, 0)) > 0)
     printf ("Socket wurde angelegt\n");
  address.sin_family = AF_INET;
  address.sin_addr.s_addr = INADDR_ANY;
  address.sin_port = htons (15000);
  setsockopt( create_socket, SOL_SOCKET,
              SO_REUSEADDR, &y, sizeof(int) );
  if (bind( create_socket,
            (struct sockaddr *) &address,
            sizeof (address)) == 0 )
     printf ("Binding Socket\n");
  listen (create_socket, 5);
  addrlen = sizeof (struct sockaddr_in);
  save_fd = fcntl( create_socket, F_GETFL );
  save_fd |= O_NONBLOCK;
  fcntl( create_socket, F_SETFL, save_fd );
  while (1) {
    new_socket = accept ( create_socket,
                          (struct sockaddr *) &address,
                          &addrlen );
    if (new_socket > 0)
       printf ("Der Client %s ist verbunden ...\n",
          inet_ntoa (address.sin_addr));
    else {
      printf("Poll: Kein Client am Socket ...\n");
      sleep(1);
      continue; /* wieder zum Schleifenanfang */
    }
    do {
      /* Socket für die Datenübertragung auf NON-Blocking */
      save_fd = fcntl( new_socket, F_GETFL );
      save_fd |= O_NONBLOCK;
      fcntl( new_socket, F_SETFL, save_fd );
      /* Daten verarbeiten */
    } while (strcmp (buffer, "quit\n") != 0);
    close (new_socket);
  }
  close (create_socket);
  return 0;
}

Das Programm bei der Ausführung:

$ gcc -o non_block non_block.c
$ ./non_block
Socket wurde angelegt
Binding Socket
Poll: Kein Client am Socket ...
Poll: Kein Client am Socket ...
Poll: Kein Client am Socket ...
Poll: Kein Client am Socket ...
Poll: Kein Client am Socket ...
...

Um also ein Socket (hier durch Socket-Deskriptor) auf nicht blockierend zu setzen, können Sie immer den folgenden Codeausschnitt einsetzen:

save_fd = fcntl( create_socket, F_GETFL );
save_fd |= O_NONBLOCK;
fcntl( create_socket, F_SETFL, save_fd );

Mehr zu fcntl() können Sie dem Kapitel 2 in diesem Buch entnehmen.

 << zurück
  
  Zum Rheinwerk-Shop
Neuauflage: Linux-UNIX-Programmierung
Neuauflage:
Linux-UNIX-
Programmierung

bestellen
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: Linux-Server






 Linux-Server


Zum Rheinwerk-Shop: Das Komplettpaket LPIC-1 & LPIC-2






 Das Komplettpaket
 LPIC-1 & LPIC-2


Zum Rheinwerk-Shop: Linux-Hochverfügbarkeit






 Linux-
 Hochverfügbarkeit


Zum Rheinwerk-Shop: Shell-Programmierung






 Shell-
 Programmierung


Zum Rheinwerk-Shop: Linux Handbuch






 Linux Handbuch


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
Info





Copyright © Rheinwerk Verlag GmbH 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern