TCP/IP-Sockets: Die Funktionen |
#include |
Jeder eröffnete Socket muss auch wieder geschlossen werden. Dies ist an sich eine Binsenweisheit. Eine Nachlässigkeit an dieser Stelle kann sich bitter rächen, da insbesondere bei Serverprozessen Verbindungen sehr oft eröffnet werden und das Fehlen weiterer Sockets meist zum Stillstand des Servers führt.
Das Schließen des Sockets erfolgt unter UNIX mit dem close-Aufruf.
Dies funktioniert bei anderen Betriebssystemen im Normalfall nicht, da
die Integration der Sockets ins System nicht so eng ist.
Meist werden Namen wie closesocket, socketclose oder soclose verwendet.
Der listen-Call gibt an, wieviele Anfragen gepuffert werden können.
In fast allen Programmen wird eine 5 verwendet.
Der accept wartet auf eine Anfrage eines Clients.
Der Aufruf liefert als Rückgabewert die Socket-ID des Partners.
Des weiteren wird per Parameter die sockaddr_in des Partners
geliefert.
Serveraufrufe: bind, listen und accept
Der Serverprozess muss von außen erreichbar sein. Dazu bekommt
er einen sogenannten well known port. Diese Nummer ist also
den Clientprozessen bekannt. Um einen Socket an diese Nummer zu
binden, wird der bind-Aufruf verwendet. Als Parameter verwendet er
den Socket und eine Struktur sockaddr_in, die diesen
Port beschreibt.
struct sockaddr_in AdrMySock, AdrPartnerSocket; ... AdrMySock.sin_family = AF_INET; AdrMySock.sin_addr.s_addr = INADDR_ANY; /* akzept. jeden */ AdrMySock.sin_port = PortNr; /* wird per getservbyname bestimmt */ bind(IDMySocket, &AdrMySock, sizeof(AdrMySock)); listen(IDMySock, 5); do { IDPartnerSocket = accept(IDMySocket, &AdrPartnerSocket, &len); |
Nicht zu vergessen: die IDPartnerSocket muss nach Ende der Kommunikation geschlossen werden, ansonsten gehen dem System nach einiger Zeit die Sockets aus.
struct sockaddr_in AdrSock; AdrSock.sin_addr = HostID; AdrSock.sin_port = PortNr; connect(IDSocket, (struct sockaddr *)&AdrSock, sizeof(AdrSock)); |
Die recv-Funktion liefert als Rückgabewert die Größe des
empfangenen Speicherbereichs. Die recv-Funktion liefert die Sendung in
Happen von maximal 1KB.
Wurden größere Pakete verschickt, müssen sie häppchenweise
gelesen werden. Das Senden ist nicht beschränkt.
Da der Rückgabewert nichts über die Grösse des tatsächlich
gesendeten Pakets aussagt, muss dies vom Programm geregelt werden. Wenn die Pakete
nicht immer gleicher Größe sind, wird die Paketlänge meist in den
ersten Bytes des ersten Paketes kodiert.
Datenaustausch: send und recv
Mit diesen beiden Aufrufen werden Daten über die bestehenden
Verbindungen transportiert. Unter UNIX können dafür auch
die Dateiaufrufe read und write verwendet werden.
Sofern nicht Funktionen sowohl mit Dateien als auch mit Sockets
arbeiten sollen, empfielt es sich aber, bei send und recv zu bleiben.
Erstens erkennt man bereits am Aufruf, dass es Netzverbindungen sind,
zweitens hat man Vorteile beim Portieren auf andere Plattformen.
Namensauflösung
Computer und Dienste werden unter TCP/IP eigentlich mit Nummern angesprochen.
Allerdings gibt es für beides
Mechanismen zur Namensauflösung.
Damit sie auch im Programm Anwendung finden, ruft man entsprechende
Funktionen auf.
struct hostent *RechnerID; struct servent *Service; RechnerID = gethostbyname("server"); /* Bestimme den Rechner namens server */ Service = getservbyname("hilfe","tcp"); /* Bestimme den Port für hilfe */ |
Das wichtigste Element der servent-Struktur ist das Feld s_port. Hierin befindet sich die Nummer des Ports, wie sie von der Funktion connect verwendet wird.
Das wichtigste Element der hostent-Struktur ist das Feld h_addr_list. Hierin befindet sich das Array der IP-Nummern des Rechners. Das Makro h_addr liefert die Nummer, wie sie in älteren Versionen üblich war. Das Feld h_length liefert die Größe einer IP-Nummer.
struct sockaddr_in AdrSock; AdrSock.sin_port = hton(110); |
Homepage | (C) Copyright 2000 Arnold Willemer |