int select( int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

Die select()-Funktion wird meistens immer dann verwendet, wenn Sockets im nicht-blockierenden Modus arbeiten. Wenn beispielsweise von mehreren Sockets Daten empfangen werden sollen, würde die recv()-Funktion den Empfang von Daten anderen Socketsblockieren. Da auch die Tastatur als eine Datei mit dem Datei-Deskriptor vom Wert 1 betrachtet wird, würden auch Eingaben von der Tastatur blockiert werden, bis Daten vom Socket empfangen werden. Dies ist im speziellen dann fatal, wenn nur in sehr großen zeitlichen Abständen Daten von einem Socket empfangen werden. Auch im Allgemeinen ist dies nicht schön und sollte deshalb vermieden werden.

Mittels der select()-Funktion können Datei-Deskriptoren (und damit auch Sockets) überprüft werden, ob Daten für den Empfang bereitstehen. Darüber hinaus bietet es die select()- Funktion an, zu überprüfen, ob ein Socket bereit ist Daten zu senden bzw. ob ein unerwartetes Ereignis aufgetreten ist (z.B. ein Socket wurde unerwartet geschlossen (reset)).

Da der Aufruf der select()-Funktion nicht blockierend sein soll, wird mittels des Parameters timeout die Zeit angegeben, wann die Funktion beendet werden soll. Stehen z.B. innerhalb dieser Zeit Daten zum Empfang bereit, dann wird die select()- Funktion frühzeitig abgebrochen.

Separat für jede Gruppe von Operationen (empfangsbereit, sendebereit und Ausnahmen) existiert eine Menge, die alle Datei- Deskriptoren enthält, die beobachtet werden sollen. Z.B. sind in der Menge readfds alle Deskriptoren enthalten, bei denen beobachtet werden soll, ob Daten zum Empfang bereitstehen. In der Menge writefds und der Menge exceptfds sind analog alle Deskriptoren enthalten, bei deren darauf geachtet werden soll, ob Daten gesendet werden können oder ein Ausnahme aufgetreten ist.

Zur Manipulation der Mengen vom Typ fd_set werden die Funktionen (genauer gesagt Makros) bereit gestellt:

Sind die Mengen readfds, writefds und execptfds initialisiert kann die select()-Funktionen aufgerufen werden:

Im Parameter nfds ist die Nummer des größten Datei-Deskriptor + 1 aus den Mengen readfds, writefds und execptfds enthalten. Zur Erinnerung: Datei-Deskriptoren sind Zahlen vom Typ int.

In den Parametern readfds, writefds und execptfds sind alle Datei-Deskriptoren enthalten, die beobachtet werden sollen.

Als Rückgabewert liefert die select()-Funktion die Anzahl der Datei-Deskriptoren, bei denen sich eine Änderung ergeben hat.

Aus der Beschreibung der select()-Funktion ist zu erkennen, dass der aufrufende Prozess solange vertagt wird, bis sich etwas bei einem zu beobachtenden Datei-Deskriptor verändert hat. Um diese Wartezeit zu begrenzen wird der optionale Parameter *timeout vom Typ struct timeval auf einen Wert ungleich NULL gesetzt.

Mittels der Variablen timeout wird eine Zeit in Sekunden und Mikrosekunden angeben:

struct timeval{
int tv_sec; // bezeichnet Sekunden
int tv_usec; // bezeichnet Mikrosekunden
}

Tritt nach Ablauf dieser Zeit keine Veränderung bei einem Datei-Deskriptor auf, dann wird die select()-Funktion frühzeitig beendet. Der Prozess kann nun andere Aufgaben ausführen. Als Rückgabewert liefern die select()-Funktion wird in diesem Fall den Wert 0. In jedem anderen Fall, z.B. bei auftretenden Fehlern, liefert die Funktion den Wert -1.

Beispiel:

int fd;
fd_set readset;
int result;
struct timeval tv;

// Initialize the set
FD_ZERO(&readset); FD_SET(fd, &readset);

// Initialize time out struct
tv.tv_sec = 1; tv.tv_usec = 0;

// select()
result =select(fd+1, &tempset, NULL, NULL,&tv);

// Check status
if (result < 0) return -1;
else if (result > 0 && FD_ISSET(fd, &tempset)){
	// receive
	result = recv(fd, buffer, len, flags);
}