If I am using select() to monitor three file descriptor sets:
if (select(fdmax+1, &read_fds, &write_fds, &except_fds, NULL) == -1) {
perror("select()");
exit(1);
} else {
...
}
Can a particular file descriptor be ready for reading AND writing AND exception handling simultaneously?
Beej's popular networking page shows a select() example in which he tests the members of the read fd_set using a for loop. Since the loop increments by one each iteration, it will necessarily test some integers that don't happen to be existing file descriptors:
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) { // we got one!!
{
...
}
}
I believe he's doing this for the sake of keeping the example code simple. Might/should one only test existing file descriptors?
Expanding a little bit with examples and @user207421 comment:
1 Can a particular file descriptor be ready for reading AND writing AND exception handling simultaneously?
Good example will be a socket, which will (almost) always be ready for writing, and will be ready for reading when data is available. It is not common to have exceptions - they are used for exceptional
situations. For example, availability of out-of-band message on TCP connections, but most applications do not use those features.
Note that 'normal' errors will be indicated in readfds
(for example, socket shutdown).
See also: *nix select and exceptfds/errorfds semantics,
Beej's popular networking page shows a select() example in which he tests the members of the read fd_set using a for loop. Since the loop increments by one each iteration, it will necessarily test some integers that don't happen to be existing file descriptors:
I believe that in this case, it is done simplify the code examples, and is a reasonable implementation for most light weight implementations. It works well if the number of non-listen connections is very small.
Worth mentioning that the 'fd_set' is implemented on Linux with a set of bits, but on Windows (winsock) as an array of fd values. A full scan on all FDs will be O(n) on Linux, and O(n*n) on Windows. This can make a big performance hit on large N for Windows app.
In large scale applications, where a server will listen to hundreds (or more) open connections, each require different actions, potentially with multiple states, the common practice will be to have the list of of active connections, and use a callback to invoke the function. This is usually implemented with an 'eventloop'. Examples include X11, rpc servers, etc.
See Also: https://en.wikipedia.org/wiki/Event_loop