Die meisten Services arbeiten verbindungsorientiert. Einige Services basieren jedoch auf der Verwendung von Datagramm-Sockets und arbeiten somit verbindungslos.
In den Beispielprogrammen verwendet der Server die folgenden Funktionen der Socket- bzw. POSIX-Schnittstelle:
socket(): einen Socket erzeugen
bind(): einem Socket einen Namen zuordnen
recvfrom(): eine Nachricht von einem Socket lesen
close(): einen Socket schließen
Das Programm wird in zwei Varianten vorgestellt:
In Beispiel 1 wird das Programm beendet, nachdem eine Nachricht gelesen wurde.
In Beispiel 2 wartet das Programm in einer Endlosschleife auf weitere Nachrichten, nachdem eine Nachricht gelesen wurde.
Beispiel 1: Verbindungsloser Server ohne Programmschleife
#include <stdio.h> #include <sys/socket.h> #include <ioctl.h> #include <signal.h> #include <netinet/in.h> #include <netdb.h> #define ERROR_EXIT(M) perror(M); exit(1) #define TESTPORT 2222 int main(int argc, char **argv) { int sock; int length; struct sockaddr_in server; char buf[1024]; /* Erzeugen des Sockets, von dem gelesen werden soll. */ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ERROR_EXIT("socket"); } /* Dem Socket unter Verwendung von Wildcards einen Namen zuordnen */ server.sin_family = AF_INET; server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_port = htons(TESTPORT); if (bind(sock, (struct sockaddr *)&server, sizeof server ) < 0) { ERROR_EXIT("bind"); } /* Lesens vom Server */ length = sizeof(server); memset(buf,0,sizeof(buf)); if (recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&server, &length) < 0) { ERROR_EXIT("recvfrom"); } else { printf("->%s\n",buf); } close(sock); return 0; }
Beispiel 2: Verbindungsloser Server mit Programmschleife
Da dieses Programm in einer Endlos-Schleife läuft, wird der Socket niemals explizit geschlossen. Allerdings werden alle Sockets automatisch geschlossen, wenn der Prozess abgebrochen wird oder sein normales Ende erreicht.
#include <sys/socket.h> #include <ioctl.h> #include <signal.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #define ERROR_EXIT(M) perror(M); exit(1) #define TESTPORT 2222 int main(int argc, char **argv) { int sock; int length; struct sockaddr_in server; char buf[1024]; /* Erzeugen des Sockets, von dem gelesen werden soll. */ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ERROR_EXIT("socket"); } /* Dem Socket unter Verwendung von Wildcards einen Namen zuordnen */ server.sin_family = AF_INET; server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_port = htons(TESTPORT); if (bind(sock, (struct sockaddr *)&server, sizeof server ) < 0) { ERROR_EXIT("bind"); } /* Beginn des Lesens vom Server */ length = sizeof(server); for (;;) { memset(buf,0,sizeof(buf)); if (recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&server, &length) < 0) { ERROR_EXIT("recvfrom"); } else { printf("->%s\n",buf); } } /* NOTREACHED */ }
Im Programm werden folgende Arbeitsschritte durchgeführt:
Die Funktion socket() erzeugt einen Kommunikationsendpunkt (Server-Socket) und den zugehörigen Deskriptor.
- Die Funktion bind() weist dem Server-Socket eine definierte Portnummer zu, sodass er über diese Portnummer vom Netzwerk aus angesprochen werden kann.
- Mit der Funktion recvfrom() wird von einem Socket des Typs SOCK_DGRAM gelesen. Als Ergebnis wird die Länge der gelesenen Nachricht geliefert.
Wenn keine Nachricht vorhanden ist, wird der Prozess blockiert, bis eine Nachricht eintrifft.
Die Beispielprogramme sind nur für die Kommunikationsdomäne AF_INET gültig. Wenn sie gemäß den Angaben in "Socket- Adressierung" und "Socket erzeugen" geändert werden, gelten sie auch für die Domäne AF_INET6.