Select

Note: An application running a single connection, typically a client app, may easily opt not to use the select function. Servers may also process isolated connections by making use of operating system support such as the unix spawn function where a new process or thread may be started for each client that connects.

Essentials

This section summarises the content on this page (read on for the full tutorial):

Select Usage

The select function allows an app to wait on multiple socket events, with the option of timing out if no events are detected within a given time interval.

Three socket event types are defined:

READA read event occurs when a monitored socket has data available such that a receive function, when issued, would not block/wait. In the case of a server this also applies to an accept of a new inbound connection.
Typically an application using select would monitor all ACTIVE connections for read activity.
WRITEA write event occurs when a monitored socket can successfully send data on the socket without blocking/waiting. This applies when either a send or a connect request completes with EWOULDBLOCK.
To avoid a loop, an application must only monitor connections after having received EWOULDBLOCK on a request i.e. sockets are normally always available to send data, so a select that monitors all sockets for write activity would return immediately.
EXCEPTIONAn exception event occurs when a monitored socket may successfully issue a receive for out-of-band data. This requires the partner app sends out-of-band data usually as part of a pre-agreed protocol. An exception event is also indicated when a socket is no longer available for any use other than close. This is the method by which an app using givesocket to pass a socket to another task, process or thread is informed that takesocket has been issued by that task, process or thread.

The sockets to be monitored are, in compiled languages typically specified using a bit map. This is a series of consecutive bytes in storage where each bit that is set represents a socket to be monitored, the first bit representing socket 0, the second socket 1 etc. With interpreted languages the socket numbers themselves are used to form either a list or array of sockets to be monitored.

Where bit maps are used it is usual for select to update the input bit map leaving set only those bits representing sockets where activity is to be notified. On some APIs separate pre-zero’d output bit map areas are passed as extra parameters to select and these are then updated by the select function leaving the input mask unchanged for re-use. In an interpreted language three lists or arrays will be returned identifying the sockets that have activity.

Typically, an application processes each bit set in the bit mask output by select, carrying out the activity for that bit map i.e. issuing a read, write or close for the socket in question. After all flagged sockets have been processed the application will again wait via another call to select.

Processing bit maps can be complex, to aid the programmer most APIs provide facilities for using a socket number to set/reset a bit and to convert a relative bit position into a socket number. These are the FD_SET, FD_CLR, FD_ISSET and FD_ZERO macros.

Select Parameter Definitions

fd countInput: This is the highest socket number to be monitored via this select. Create an efficient app by resisting the temptation to set this field to the maximum number of connections supported.
Address of a bit map or list of sockets to be monitored for READ activityIn(Out)put: This is the “bit map”/”socket list” identifying the sockets to be monitored for read activity.
When using bit maps select updates the input map to return only those monitored sockets where a receive would complete without blocking i.e. without placing the application in a wait state.
When using socket lists select returns a list of sockets in an API specific manner.
Address of a bit map or list of sockets to be monitored for WRITE activityIn(Out)put: This is the “bit map”/”socket list” identifying the sockets to be monitored for write activity.
When using bit maps select updates the input map to return only those monitored sockets where a send would complete without blocking i.e. without placing the application in a wait state.
When using socket lists select returns a list of sockets in an API specific manner.
Address of a bit map or list of sockets to be monitored for an EXCEPTION conditionIn(Out)put: This is the “bit map”/”socket list” identifying the sockets to be monitored for exception conditions.
When using bit maps select updates the input map to return only those monitored sockets where an exception condition has been identified.
When using socket lists select returns a list of sockets in an API specific manner.
Note: On some APIs the above 3 parameters (address pointers) may be used as purely input parameters with an additional 3 parameters specifying output list locations.
Timeout valueIn(Out)put: This is the length of time that this select should wait for socket activity, 0 indicates an indefinite wait for activity. When socket activity has been detected, some APIs have select update this field with the remaining time for the requested timeout value. A programmer may then re-issue select without modifying this field to have select function as an interval timer or reset the field to function as an inactivity timer.

Returns: A numeric code as follows:

PositiveThe number of sockets being returned where activity has been detected.
0 (zero)No activity was detected before the timeout value was reached.
NegativeUsually -1 indicating an error occurred, refer to the ERRNO value for an explanation of the error.

Select error handling

Since select involves an application wait for activity, it is tightly linked to the dispatching mechanisms of the underlying OS e.g. unix environments may need to handle and check for signal type interrupts, this is integrated in the pselect function.

Not an error but in a similar vein, IBM environments may need to integrate select into an application developed task level dispatcher using an asynchronous select with ECB lists or alternatively extend select functionality with selectx.

Simple Select example

The simplest use of select is to attach a timeout value to a receive, thereby avoiding endless waits. That we are prepared to wait indicates that this is a simple client with a single connection, knowing our environment we can assume use of socket number 0. Our coding would then go like this:

   
   1.   moveto readmask, 0x00
   2.   retc = send( socNum, addrData, lenData, 0)
   3.   fd_set(socNum, addrReadmask)
   4.   retc = select( socNum+1, addrReadmask, 0, 0, 30 sec)
   5.   if (retc < 1) {
   6.      issue timeout or error message
           close socket
           exit
        }
   7.   retc = receive( socNum, addrBuf, lenBuf, 0)
   

Where the numbered steps represent:

  1. Declare or obtain storage for a read mask, ensuring that it is zero’d.
  2. Send whatever data forms our request for the server.
  3. Set the read mask to indicate monitoring of the socket is required.
  4. Assign to retc the value returned by the select that uses our read mask as input and a fixed timeout value of 30 seconds.
  5. If retc is negative we have had an error and need to report it, if retc is zero then the select timed out.
  6. If error or timed out then issue message, close the socket and exit.
  7. If activity detected, it can only be for the one socket, issue the receive to pick up the waiting data, or if EOF (0 length data) close the socket.

 

Continue with the Tutorial

Shutdown
Close
Next
Sockets
Contents
Contents
Server
Connections
Prev