Introducing the select(2) Function
The select(2) function permits you to block the execution of your server until there is something for the server to do. More specifically, it permits the caller to know when
- There is something to read from a file descriptor.
- Writing to the file descriptor will not block the execution of the server program.
- An exception has occurred on a file descriptor.
You will recall that the handle to a socket is a file descriptor. The select(2) function will notify the server when something has happened on any one of a specified set of connected client sockets. In effect, this allows the server to process multiple clients in a very efficient manner.
As pointed out previously, the server is interested when any new request data is coming in from a client's socket. To know this, the server needs to know when there is data to be read from a
particular client's socket.
When sending data back to the client, it is important for the server to know that it can write the data to the socket without being blocked. If the connected client, for example, requests a large amount of information to be returned, the server will have to write that information to the socket. If the client software is faulty or is slow reading the data at its end, the server will block for a long time, while attempting to write the rest of the result data. This has the consequence that all other clients that are connected to the server must now also wait. This is clearly undesirable, since each client must be serviced as expeditiously as possible.
If your server must also process out-of-band data (I will explain this very soon in coming posts “Out -of-Band Data”), then you will be interested in exceptions that might take place on the socket.
Now turn your attention to the synopsis for the select(2) function:
* socket select function & return values
int select(int n,
struct timeval *timeout);
This function requires five input arguments:
- The maximum number (n) of file descriptors to test. This value is at least the highest file descriptor number plus one, since descriptors start at zero.
- The set of file descriptors (readfds) that are to be tested for read data.
- The set of file descriptors (writefds) that are to be tested for writability.
- The set of file descriptors (exceptfds) that are to be tested for exceptions.
- The pointer (timeout) to the timeout requirement, which is to be applied to this function call.(using struct timeval)
This pointer may be NULL, indicating that there is no timeout (the function call may block forever).
The return results from the select(2) function can be summarized as follows:
- A return value of -1 indicates that an error in the function call has occurred. The value of errno should be consulted for the nature of the error.
- A return value of zero indicates that a timeout has occurred without anything interesting happening.
- A return value greater than zero indicates the number of file descriptors where something of interest has occurred.