select()

The select() call monitors activity on a set of sockets looking for sockets ready for reading, writing, or with an exception condition pending.

#include <manifest.h>
#include <socket.h>
#include <bsdtypes.h>
#include <bsdtime.h>
 
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout)
Parameter
Description
nfds
The number of socket descriptors to be checked. This value should be one greater than the greatest number of sockets to be checked.

You can use the select() call to pass a bit set containing the socket descriptors for the sockets you want checked. The bit set is fixed in size using one bit for every possible socket. Use the nfds parameter to force select() to check only a subset of the allocated socket bit set.

If your application allocates sockets 3, 4, 5, 6, and 7, and you want to check all of your allocations, nfds should be set to 8, the highest socket descriptor you specified, plus 1. If your application checks sockets 3 and 4, nfds should be set to 5.

Socket numbers are assigned starting with number 3 because numbers 0, 1, and 2 are used by the C socket interface.

readfds
Points to a bit set of descriptors to check for reading.
writefds
Points to a bit set of descriptors to check for writing.
exceptfds
Points to a bit set of descriptors to check for exception conditions pending.
timeout
Points to the time to wait for select() to complete.

If timeout is not a NULL pointer, it specifies a maximum time to wait for the selection to complete. If timeout is a NULL pointer, the select() call blocks until a socket becomes ready. To poll the sockets and return immediately, timeout should be a non-NULL pointer to a timeval structure with a value of 0.

If you are using both AF_INET and AF_IUCV sockets in the socket descriptor sets, the timer value is ignored and processed as if timeout were a non-NULL pointer to a timeval structure with a value of 0.

To use select() as a timer in your program, do either of the following:
  • Set the read, write, and except arrays to 0.
  • Set nfds to be a NULL pointer.

To understand the implementation of the select() call, you must understand the difference between a socket and a port. TCP/IP defines ports to represent a certain process on a certain machine. A port represents the location of one process; it does not represent a connection between processes. In the MVS™ programming interface for TCP/IP, a socket describes an endpoint of communication. Therefore, a socket describes both a port and a machine. Like file descriptors, a socket is a small integer representing an index into a table of communication endpoints in a TCP/IP address space.

To test more than one socket at a time, place the sockets to be tested into a bit set of type FD_SET. A bit set is a string of bits that when X is an element of the set, the bit representing X is set to 1. If X is not an element of the set, the bit representing X is set to 0. For example, if Socket 33 is an element of a bit set, then bit 33 is set to 1. If Socket 33 is not an element of a bit set, then bit 33 is set to 0.

Because the bit sets contain a bit for every socket that a process can allocate, the size of the bit sets is constant. The function getdtablesize() returns the number of sockets that your program can allocate. If your program needs to allocate a large number of sockets, use getdtablesize() and maxdesc() to increase the number of sockets that can be allocated. Increasing the size of the bit sets must be done when you compile the program. To increase the size of the bit sets, define FD_SETSIZE before including BSDTYPES.H. The largest value of any socket is FD_SETSIZE, defined to be 255 in BSDTYPES.H.

The following macros can manipulate bit sets.
Macro
Description
FD_ZERO(&fdset)
Sets all bits in bit set fdset to 0. After this operation, the bit set does not contain sockets as elements. This macro should be called to initialize the bit set before calling FD_SET() to set a socket as a member.
FD_SET(sock, &fdset)
Sets the bit for the socket sock to 1, making sock a member of bit set fdset.
FD_CLR(sock, &fdset)
Clears the bit for the socket sock in bit set fdset. This operation sets the appropriate bit to 0.
FD_ISSET(sock, &fdset)
Returns nonzero if sock is a member of the bit set fdset. Returns 0 if sock is not a member of fdset. (This operation returns the bit representing sock.)
A socket is ready to be read when incoming data is buffered for it, or when a connection request is pending. A call to accept(), read(), recv(), or recvfrom() does not block. To test whether any sockets are ready to be read, use FD_ZERO() to initialize the readfds bit set and invoke FD_SET() for each socket to be tested.

A socket is ready to be written if there is buffer space for outgoing data. A socket is ready for reading if there is data on the socket to be received. For a nonblocking stream socket in the process of connecting the connect() will return with a -1. The program needs to check the errno. If the errno is EINPROGRESS] the socket is selected for write when the connect() completes. In the situation where the errno is not EINPROGRESS, the socket will still be selected for write which indicates that there is a pending error on the socket. A call to write(), send(), or sendto() does not block providing that the amount of data is less than the amount of buffer space. If a socket is selected for write, the amount of available buffer space is guaranteed to be at least as large as the size returned from using SO_SNDBUF with getsockopt(). To test whether any sockets are ready for writing, initialize writefds using FD_ZERO(), and use FD_SET() for each socket to be tested.

The select() call checks for a pending exception condition on the given socket to indicate that the target program has successfully called takesocket(). When select() indicates a pending exception condition, your program calls close() to close the given socket. A socket has exception conditions pending if it has received out-of-band data. A stream socket that was given using givesocket() is selected for exception when another application successfully takes the socket using takesocket().

The programmer can pass NULL for any bit sets without sockets to test. For example, if a program need only check a socket for reading, it can pass NULL for both writefds and exceptfds.

Because the sets of sockets passed to select() are bit sets, the select() call must test each bit in each bit set before polling the socket for status. For efficiency, the nfsd parameter specifies the largest socket passed in any of the bit sets. The select() call then tests only sockets in the range 0 to nfsd-1. Variable nfsd can be the result of getdtablesize(), but if the application has only two sockets and nfsd is the result of getdtablesize(), select() tests every bit in each bit set.

Return values

The total number of ready sockets in all bit sets is returned. The value -1 indicates an error; check errno. The value 0 indicates an expired time limit. If the return value is greater than 0, the sockets that are ready in each bit set are set to 1. Sockets in each bit set that are not ready are set to 0. Use macro FD_ISSET() with each socket to test its status.
Errno
Description
EBADF
One of the bit sets specified an incorrect socket. [FD_ZERO() was probably not called before the sockets were set.]
EFAULT
One of the bit sets pointed to a value outside the caller address space.
EINVAL
One of the fields in the timeval structure is not valid.
Note: If the number of ready sockets is greater than 65535, only 65535 is reported.

Example

In the following example, select() is used to poll sockets for reading (socket r), writing (socket w), and exception (socket e) conditions.
/* sock_stats(r, w, e) - Print the status of sockets r, w, and e. */
int sock_stats(r, w, e)
int r, w, e;
{
   fd_set reading, writing, except;
   struct timeval timeout;
   int rc, max_sock;
 
   /* initialize the bit sets */
   FD_ZERO( &reading );
   FD_ZERO( &writing );
   FD_ZERO( &except );
 
   /* add r, w, and e to the appropriate bit set */
   FD_SET( r, &reading );
   FD_SET( w, &writing );
   FD_SET( e, &except );
 
   /* for efficiency, what's the maximum socket number? */
   max_sock = MAX( r, w );
   max_sock = MAX( max_sock, e );
   max_sock ++;
 
   /* make select poll by sending a 0 timeval */
   memset( &timeout, 0, sizeof(timeout) );
 
   /* poll */
   rc = select( max_sock, &reading, &writing, &except, &timeout );
 
   if ( rc < 0 ) {
        /* an error occurred during the select() */
        tcperror( "select" );
   }
   else if ( rc == 0 ) {
        /* none of the sockets were ready in our little poll */
        printf( "nobody is home.\n" );
   } else {
        /* at least one of the sockets is ready */
        printf("r is %s\n", FD_ISSET(r,&reading) ? "READY" : "NOT READY");
        printf("w is %s\n", FD_ISSET(w,&writing) ? "READY" : "NOT READY");
        printf("e is %s\n", FD_ISSET(e,&except)  ? "READY" : "NOT READY");
   }
}
 

Related calls

getdtablesize(), maxdesc(), selectex()