Netzwerk
TCP/IP (Webserver)
4 Client-Server Kommunikation

Wie schon gezeigt, sind Sockets für die Kommunikation bei TCP/IP geeignet. Diese Kommunikationsart über Rechnergrenzen hinweg werden nun näher betrachtet.

 


4.1 Client und Server

Man muss bei der Kommunikation zwischen einem Client und einem Server unterscheiden. Der Client fragt an, der Server beantwortet die Frage. Bei den beiden Endpunkten einer Verbindung ist jeweils einer ein Client, der andere ein Server. Eine Client-Client oder eine Server-Server Kommunikation gibt es nicht.

 


4.2 Erzeugung von Sockets

Zur Erzeugung eines Socket steht die Funktion

 

#include <sys/types.h>

int socket ( int domain, int typem, int protocoll );

return: der Socket oder –1

 

zur Verfügung. Hiermit wird ein Socket erzeugt, der aber noch nicht initialisiert ist. Es wird ein Protokoll festgelegt, aber noch nicht mit einer Resource gekoppelt. Es ist also noch kein Zugriff darauf möglich.

 

Für den Parameter domain stehen folgende Werte zur Auswahl

AF_UNIX PF_UNIX Unix Domain Socket

AF_INET PF_INET TCP/IP

AF_AX25 PF_AX25 AX 25 (Amateurradio)

AF_IPX PF_IPX Novell IPX

AF_APPLETALK PF_APPLETALK Appletalt DDS

AF_NETROM PF_NETROM NetROM (Amateurradio)

 

Beim Parameter typ wird angegeben:

Streaming SOCK_STREAM

Datagramm SOCK_DGRAM

 

Für das protocoll wird meist 0 angegeben, was dem Standardprotokoll für die Protokollart entspricht

PF_INET mit Stream TCP

PF_INET mit Datagramm UDP

 


4.3 Serverseitige Initialisierung

Auf Serverseite wird die Verbindung dahingehend vorbereitet, das auf Anfragen gewartet werden kann. Hierbei werden einige weitere Funktionen benötigt. Mit

int bind ( int sockfd, struct sockaddr *addr, int adrdlen );

wird ein Server-Socket an eine Adresse gebunden.

Hierbei ist sockfd der Socket Deskriptor, der von der socket() Funktion zurückgegeben wurde. Der Parameter addr enthält die zu bindende Adresse. Die Adresslänge addrlen ist einfach der sizeof() des Typs.

 

Um dem Betriebssystem mitzuteilen, das Anfragen entgegengenommen werden können, ruft man die Funktion

int listen ( int sockfd, int backlog );

auf.

 

Hierbei ist sockfd der Socket Deskriptor. Der Parameter backlog legt die maximale Anzahl von anstehenden Verbindungen (pending) fest. Stehen weitere Verbindungen an, so werden diese abgelehnt und der anfragende Client bekommt eine Fehlermeldung, ohne das der Server die Anfrage bearbeiten kann.

 

Anmerkung: Bei BSD ist backlog mit maximal 5 belegbar. Um Kompatibilität zu anderen Betriebssystemen zu wahren, sollte man diesen Wert nicht überschreiten.

 

Mit der normalerweise blockierenden Funktion

int accept ( int sockfd, struct sockaddr *adr, int *addrlen);

wird die Clientanforderung entgegengenommen. Damit steht die Verbindung vollständig.

 

Geliefert bekommt man als Funktionsrückgabe den Clientsocket, in den man die Antwort schreiben kann. Desweitern wird die Clientadresse in der Struktur geliefert.

 

Anmerkung: Blockierend heißt, das der Aufruf von accept() erst dann zurückkehrt, wenn eine Clientanfrage ansteht. Bis dahin hat die accept() Funktion die Kontrolle. Über die Funktion fcntl() kann der Socket als nichtblockierend markiert werden. Damit würde accept() sofort zurückkehren. Um dann festzustellen, ob eine Clientanforderung ansteht, benutz man die Funktion select().

 


4.4 Clientseitige Initialisierung

Nachdem bereits ein Server auf Anfragen wartet, kann ein Client seine Anfragen an diesen stellen.

 

Zuerst erzeugt der Client – wie der Server – einen Socket mit der socket() Funktion.

 

Ein Client könnte auch mit bind() eine Adresse binden. Dies ist jedochselten notwendig, da der Client nicht an seiner eigenen Adresse interessiert ist. Für den Verbindungsaufbau zum Server nutzt er direkt die Funktion

int connect ( int sockfd, struct sockaddr *serv, int addrlen ) ;

return:  0=Erfolg, -1=Fehler

 

Hierbei ist der Parameter serv die Serversocket-Adresse, mit der der Client eine Verbindung aufbauen will.

 

Wird die Verbindung getrennt, dann soll der Socket mit der Funktion closesocket() geschlossen werden, um die Resourcen wieder frei zu geben.

Hier ein Vebindungsaufbau im Überblick

 

<Grafik>

 

Nun können Daten mit recv() und send() empfangen und gesendet werden.

 

Anmerkung: Bei Linux/Unix ist der Socket Deskriptor ein File Deskriptor, wodurch alle Datei Operationen möglich sind.

 

Anmerkung: Bei Windows muss zur Initialisierung der Socket Unterstützung die Funktion WSAStartup(MAKEWORD(1,1, &wsa)) aufgerufen werden, bevor die erste Kommunikationsfunktion aufgerufen wird.

 



Last update:  13.07.2005