Oracle® Solaris 11.2 Programming Interfaces Guide

Exit Print View

Updated: July 2014
 
 

Input/Output Multiplexing

Requests can be multiplexed among multiple sockets or multiple files. Use select(3C) to multiplex:

#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
...
fd_set readmask, writemask, exceptmask;
struct timeval timeout;
...
select(nfds, &readmask, &writemask, &exceptmask, &timeout);

The first argument of select(3C) is the number of file descriptors in the lists pointed to by the next three arguments.

The second, third, and fourth arguments of select(3C) point to three sets of file descriptors: a set of descriptors to read on, a set to write on, and a set on which exception conditions are accepted. Out-of-band data is the only exceptional condition. You can designate any of these pointers as a properly cast null. Each set is a structure that contains an array of long integer bit masks. Set the size of the array with FD_SETSIZE, which is defined in select.h. The array is long enough to hold one bit for each FD_SETSIZE file descriptor.

The macros FD_SET (fd, &mask) and FD_CLR (fd, &mask) add and delete, respectively, the file descriptor fd in the set mask. The set should be zeroed before use and the macro FD_ZERO (&mask) clears the set mask.

The fifth argument of select(3C) enables the specification of a timeout value. If the timeout pointer is NULL, select(3C) blocks until a descriptor is selectable, or until a signal is received. If the fields in timeout are set to 0, select(3C) polls and returns immediately.

The select(3C) routine normally returns the number of file descriptors that are selected, or a zero if the timeout has expired. The select(3C) routine returns −1 for an error or interrupt, with the error number in errno and the file descriptor masks unchanged. For a successful return, the three sets indicate which file descriptors are ready to be read from, written to, or have exceptional conditions pending.

Test the status of a file descriptor in a select mask with the FD_ISSET (fd, &mask) macro. The macro returns a nonzero value if fd is in the set mask. Otherwise, the macro returns zero. Use select(3C) followed by a FD_ISSET (fd, &mask) macro on the read set to check for queued connect requests on a socket.

The following example shows how to select on a listening socket for readability to determine when a new connection can be picked up with a call to accept(3SOCKET). The program accepts connection requests, reads data, and disconnects on a single socket.

Example 7-4  Using select(3C) to Check for Pending Connections
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time/h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#define TRUE 1
/*
 * This program uses select to check that someone is
 * trying to connect before calling accept.
 */
main() {
    int sock, length;
    struct sockaddr_in6 server;
    int msgsock;
    char buf[1024];
    int rval;
    fd_set ready;
    struct timeval to;
    /* Open a socket and bind it as in previous examples. */
    /* Start accepting connections. */
    listen(sock, 5); 
    do {
        FD_ZERO(&ready);
        FD_SET(sock, &ready);
        to.tv_sec = 5;
        to.tv_usec = 0;
        if (select(sock + 1, &ready, (fd_set *)0, 
                   (fd_set *)0, &to) == -1) {
            perror("select");
            continue;
        }
        if (FD_ISSET(sock, &ready)) {
            msgsock = accept(sock, (struct sockaddr *)0, (int *)0);
            if (msgsock == -1)
                perror("accept");
            else do {
                memset(buf, 0, sizeof buf);
                if ((rval = read(msgsock, buf, sizeof(buf))) == -1)
                    perror("reading stream message");
                else if (rval == 0)
                    printf("Ending connection\n");
                else
                    printf("-->%s\n", buf);
            } while (rval > 0);
            close(msgsock);
        } else
            printf("Do something else\n");
        } while (TRUE);
    exit(0);
}

In previous versions of the select(3C) routine, its arguments were pointers to integers instead of pointers to fd_sets. This style of call still works if the number of file descriptors is smaller than the number of bits in an integer.

The select(3C) routine provides a synchronous multiplexing scheme. The SIGIO and SIGURG signals, which is described in Advanced Socket Topics, provide asynchronous notification of output completion, input availability, and exceptional conditions.