Die Seite des Servers wurde bereits im Beispiel im Abschnitt "Verbindungsorientierter Server bei AF_INET / AF_INET6" dargestellt. Im Programmcode können Sie deutlich die separaten, asymmetrischen Rollen von Client und Server erkennen. Der Server wartet als passive Instanz auf Verbindungsanforderungen des Clients, während der Client als aktive Instanz eine Verbindung anstößt.
Im Folgenden werden die Schritte näher betrachtet, die vom Client-Prozess des remote login durchgeführt werden. In den Programmbeispielen verwendet der Client die folgenden Funktionen der Socket-Schnittstelle:
socket(): Socket erzeugen
gethostbyname() / getipnodebyname(): Rechnereintrag abfragen
connect(): auf einem Socket eine Verbindung anfordern
send(): Daten auf einen Socket schreiben
soc_close(): Socket schließen
Beispiel: Verbindungsorientierter Client bei AF_INET
#include <stdio.h> #include <sys.types.h> #include <sys.socket.h> #include <netinet.in.h> #include <netdb.h> #include <sys.uio.h> main(argc, argv) int argc; char *argv[]; { #define TESTPORT 2222 #define DATA "Here's the message ..." int sock, length; struct sockaddr_in client; struct hostent *hp; char buf[1024]; /* Socket erzeugen */ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("Create stream socket"); exit(1); } /* Ausfüllen der Adress-Struktur */ client.sin_family = AF_INET; client.sin_port = htons(TESTPORT); hp = gethostbyname(argv[1]); if (hp == NULL) { fprintf(stderr,"%s: unknown host\n", argv[1]); exit(1); } memcpy((char *) &server.sin_addr, (char *)hp->h_addr, hp->h_length); /* Verbindung starten */ if ( connect(sock, &client, sizeof(client) ) < 0 ) { perror("Connect stream socket"); exit(1); } /* Auf den Socket schreiben */ if ( send(sock, DATA, sizeof DATA, 0) < 0) { perror("Write on stream socket"); exit(1); } soc_close(sock); }
Beispiel: Verbindungsorientierter Client bei AF_INET6
#include <stdio.h> #include <sys.types.h> #include <sys.socket.h> #include <netinet.in.h> #include <netdb.h> #include <sys.uio.h> main(argc, argv) int argc; char *argv[]; { #define TESTPORT 2222 #define DATA "Here's the message ..." int sock, length; int error_num; struct sockaddr_in6 client; struct hostent *hp; char buf[1024]; /* Socket erzeugen */ sock = socket(AF_INET6, SOCK_STREAM, 0); if (sock < 0) { perror("Create stream socket"); exit(1); } /* Ausfüllen der Adress-Struktur */ client.sin6_family = AF_INET6; client.sin6_port = htons(TESTPORT); hp = getipnodebyname(argv[1], AF_INET6, 0, &error_num); if ((hp == NULL) || (error_num != NETDB_SUCCESS)) { fprintf(stderr,"%s: unknown host\n", argv[1]); exit(1); } memcpy((char *) &CLIENT.sin6_addr, (char *)hp->h_addr, hp->h_length); /* Freigabe des dynamischen Speichers von hostent */ freehostent (hp); /* Verbindung starten */ if ( connect(sock, &client, sizeof(client) ) < 0 ) { perror("Connect stream socket"); exit(1); } /* Auf den Socket schreiben */ if ( send(sock, DATA, sizeof DATA, 0) < 0) { perror("Write on stream socket"); exit(1); } soc_close(sock); }
In den Programmbeispielen zu AF_INET und AF_INET6 werden folgende Arbeitsschritte durchgeführt:
- Der Client erzeugt mit der Funktion socket() einen Kommunikationsendpunkt (Socket) und den zugehörigen Deskriptor.
Mit gethostbyname() ermittelt der Client die Adresse des Rechners (gilt nur für AF_INET). Der Rechnername wird als Parameter übergeben.
Mit getipnodebyname() ermittelt der Client die IPv6-Adresse des als Parameter übergebenen Rechnernamens. Diese neue Funktion könnte auch für das AF_INET-Beispiel verwendet werden. Danach muss für den gewünschten Rechner eine Verbindung zum Server hergestellt werden. Zu diesem Zweck initialisiert der Client die Adress-Struktur.Die Verbindung wird mit connect() aufgebaut.
Nach dem Verbindungsaufbau werden mit der Funktion send() Daten auf den Socket geschrieben.
Mit der Funktion soc_close() wird der erzeugte Socket wieder geschlossen.