6.1.2. Datagramm- und Stream-Sockets

Die Socket-Schnittstelle besteht aus einer Reihe von Systemrufen (bzw. Bibliotheksfunktionen), die durch Klient und Server in einer bestimmten Reihenfolge zu verwenden sind. Am einfachsten ist die Situation bei UDP. In Verallgemeinerung des UDP-Konzepts stehen hier die Datagramm-Sockets zur Verfügung:

Bei der Erläuterung der Socket-Systemrufe brauchen wir noch das Konzept der Socketadresse. Darunter versteht man die Zusammenfassung aus

Die hier verwendeten Socket-Systemrufe und deren Parameter sind nachfolgend aufgeführt:

Systemruf Funktion Parameter
socket Erzeugung eines Sockets Protokollfamilie (z.B. Internet) und Sockettyp (Datagramm, Stream, ...)
bind Der (lokale) Socket erhält eine Socketadresse.

Der Aufruf von bind() ist für Klienten optional. Falls er nicht erfolgt, weist die Implementierung (der Betriebssystemkern) dem Datagramm-Socket beim ersten sendto() eine geeignete IP-Adresse und einen freien Port zu. Laut Stevens verzichten sowohl UDP- als auch TCP-Klienten in der Regel auf ein explizites bind().

eigene Socketadresse
sendto Senden von Daten Daten und Ziel-Socketadresse
recvfrom Empfangen von Daten liefert Daten und Socketadresse des Absenders
close Schließen eines Sockets oder einer Datei Deskriptor des Sockets oder der Datei

Diese Beschreibung ist noch unabhängig von der verwendeten Programmiersprache. Für eine konkrete Sprache gibt es dann eine Abbildungsvorschrift. Die für C gültigen Festlegungen können Sie sich auf jedem Unix-ähnlichen System in den Handbuchseiten anschauen (man socket, man bind, ...).

Bei TCP wird bekanntlich eine (zuverlässige) Bytestrom-Übertragung realisiert. Dazu gibt es die Stream-Sockets:

Hier brauchen wir einige weitere Systemrufe:

Systemruf Funktion Parameter
listen Herstellen der "Annahmebereitschaft" des Servers maximale Zahl der "wartenden" Verbindungswünsche
accept wartet auf Verbindungsaufnahme seitens eines Klienten kann Klienten-Socketadresse liefern, wenn gewünscht
connect

Der Aufruf von bind() vor connect() ist für Klienten zulässig, aber unüblich. Der Verzicht auf ein explizites bind() bewirkt, daß die Implementierung (der Betriebssystemkern) dem Stream-Socket bei connect() eine geeignete IP-Adresse und einen freien Port zuweist.

Aufbau einer TCP-Verbindung Socketadresse des Servers
read Lesen von Daten aus einer Datei oder von einem Socket Deskriptor des Sockets oder der Datei, Datenpuffer und max. Anzahl zu lesender Bytes
write Schreiben von Daten in eine Datei oder auf einen Socket Deskriptor des Sockets oder der Datei, Datenpuffer und Anzahl der zu schreibenden Bytes
close Schließen eines Sockets oder einer Datei Deskriptor des Sockets oder der Datei

Nach der erfolgreichen Verbindungsaufnahme werden die Systemrufe read, write und close genutzt. Das sind keine speziellen Socket-Systemrufe, sondern dieselben Systemrufe, wie sie auch zum Lesen, Schreiben und Schließen von Files und Peripheriegeräten verwendet werden. Wir erkennen die interessante Eigenschaft, daß sich ein Stream-Socket nach der Verbindungsaufnahme (weitgehend) wie eine Datei verhält, was natürlich die Softwareentwicklung vereinfacht.

Wenn ein Partner seine Hälfte der TCP-Verbindung durch close beendet, wird dem anderen Partner bei read das Dateiende signalisiert, worauf dieser in der Regel mit einem eigenen close reagiert.


Vertiefung:

Hier finden Sie die C-Quelltexte für eine sehr einfache Klient-Server-Anwendung unter Nutzung der beiden Socket-Typen:

Datagramm-Socket (UDP) Stream-Socket (TCP)
Klient: udpcli.c tcpcli.c
Server: udpserv.c tcpserv.c

Unter Linux können Sie die Quelltexte so übersetzen:

   gcc -o udpcli udpcli.c
   gcc -o udpserv udpserv.c
   gcc -o tcpcli tcpcli.c
   gcc -o tcpserv tcpserv.c
Die Programme udpcli, udpserv, tcpcli und tcpserv sind auch auf hydra.informatik.tu-chemnitz.de unter /usr/local/bin installiert.

Als erstes sollten Sie den Server starten. Er erwartet eine Portnummer auf der Kommandozeile. Sie werden merken, daß Sie "niedrige" Portnummern (< 1024) nur als Superuser verwenden können. Das soll verhindern, daß ein normaler Nutzer z.B. eine Simulation das Telnet-Servers startet (mit der er dann Paßwörter "einsammelt"!).

Der Klient erwartet den Namen des Serverrechners, den Serverport und eine Nachricht auf der Kommandozeile, z.B.

  udpcli localhost 4444 "erster UDP-Test"
Der Server tcpserv ist auch mit einem Telnet-Klienten ausprobierbar!

Literatur-Empfehlungen:

Stevens, W.R.: Unix Network Programming, Volume 1
Networking APIs: Socket und XTI
Prentice Hall, Englewood Cliffs, 2. Aufl., 1998, ISBN 0-13-490012-X, 1009 S.

Comer,D.E.: Internetworking with TCP/IP.
Volume III: Client-Server Programming and Applications
Prentice Hall, Englewood Cliffs, 1993, ISBN 0-13-020272-X, 498 S.

Quinn, B.; Shute, D.: Windows Sockets Network Programming.
Addison Wesley, 1996, ISBN 0-201-63372-8, 637 S.


© Uwe Hübner, 24.2.1999