Your Browser is not longer supported

Please use Google Chrome, Mozilla Firefox or Microsoft Edge to view the page correctly
Loading...

{{viewport.spaceProperty.prod}}

Multiplexing input/output with the select() function

&pagelevel(4)&pagelevel

select() enables a program to monitor several connections simultaneously.

The following program section illustrates the use of select().

#include <sys.time.h>
#include <sys.types.h>
...
char *readmask, *writemask, *exceptmask; 
struct timeval timeout;
int nfds:
 ...
select(nfds, readmask, writemask, exceptmask, &timeout);

The parameters required by select() are three pointers to one bit mask each, which represents a set of socket descriptors:

  • select() uses the bit mask passed with readmask to test from which sockets data can be read.

  • select() uses the bit mask passed with writemask to test to which sockets data can be written.

  • select() uses the bit mask passed with exceptmask to test which sockets have an exception pending.
    The exceptmask parameter is not evaluated by SOCKETS(BS2000) at present.

The bit masks for the individual descriptor sets are stored as bit fields in integer strings. The maximum required size of the bit fields can be determined via the getdtablesize() function (see section "getdtablesize() - get size of descriptor table"). The required memory should be requested from the system dynamically.

The nfds parameter specifies how many bits or descriptors are to be tested:
select() tests bits 0 to nfds-1 in each bit mask.
If you are not interested in one of the pieces of information (read, write or pending exceptions), you should pass the null pointer with the select() call for the parameter concerned.

You can modify the bit masks with macros. You should, in particular, set the bit masks to 0 before modifying them. The bit mask manipulation macros are described in section "select() - multiplex input/output" under the functional description of select().

You can use the timeout parameter to define a timeout value if the selection process is to be limited to a predefined time. If you pass the null pointer with timeout, the execution of select() blocks for an unspecified time.
You can set polling by passing timeout a pointer to a timeval variable whose components are all set to 0.

After successful execution, the value returned by select() specifies the number of selected descriptors. The bit masks then indicate:

  • which descriptors are ready for reading

  • which descriptors are ready for writing

If select() terminates with a timeout, it returns the value 0. The bit masks are then unchanged.
If select() terminates with an error, it returns the value “-1” and the appropriate error code in errno. The bit masks are then unchanged.

After select() has been executed successfully, use the FD_ISSET(fd, &mask) macro call to check the status of a descriptor fd. The macro returns a value not equal to 0 if fd is a member of bit mask mask; otherwise, the value 0.

You can determine whether connection requests to a socket fd are waiting for acceptance by accept() by checking the “read” readiness of socket fd. To do this, you call select() and then the FD_ISSET (fd, &mask) macro. If FD_ISSET returns a value not equal to 0, this indicates “read” readiness of socket fd: which means that a connection request is pending on socket fd.

 
Example: Using select() to test for pending connection requests

The program code (for AF_INET) below results in a connection request being waited for. When it arrives, it is accepted and the program is terminated.

#include <stdlib.h>
#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
#define TESTPORT 5555
/*
 * This program uses select() to test whether someone is trying to set up 
 * a connection and then calls accept().
 */
  
main()
{
   int sock;
   struct sockaddr_in server;
   struct sockaddr_in client;
   int clientlen;
   int msgsock;
   int fdsize;
   char * ready;
   struct timeval to;
   memset(&server,'\0',sizeof(server));
   memset(&client,'\0',sizeof(client));
   clientlen = sizeof(client);
  
    /* Request memory for testing the socket descriptors using 
    soc_select() */
   if ((fdsize = getdtablesize()) < 0) {
             perror("get fd_size");
             exit(1);
}
      if (ready = ((fd_set *) memalloc(fdsize/8) == NULL))  {
         perror("no memory space");
         exit(1);
}
      /* Create socket. */
      sock = socket(AF_INET, SOCK_STREAM, 0);
      if (sock < 0) {
           perror("opening stream socket");
           exit(1);
   }
   /* Assign the socket a name using wildcards */
   server.sin_family = AF_INET;
   server.sin_addr.s_addr = htonl(INADDR_ANY);
   server.sin_port = htons(TESTPORT);
   if (bind(sock, (struct sockaddr *)&server, sizeof server) < 0) {
           perror("binding stream socket");
           exit(1);
   }
      /* Start acceptance of connections. */
      listen(sock, 5);
      do {
              memset(ready, 0, fdsize/8);
              FD_SET(sock, (fd_set *)&ready);
              to.tv_sec = 5;
              to.tv_usec=0;
              if (select(sock + 1, (fd_set *)ready, (fd_set *)0,
                (fd_set *)0, &to) < 0) {
                      perror("select");
                      continue;
              }
         if (FD_ISSET(sock, (fd_set *)ready)) {
         msgsock = accept(sock, (struct sockaddr *)&client, &clientlen);
  
         if (msgsock >= 0)
           {
            /* Successful acceptance of request to establish connection*/
            /* Follow-up processing of the data which is transferred */
            /* via this connection */
            printf("End of program after successful conection setup\n");
            break;
           }
         else
           {
            /* An error has occurred */
            /* Error message and possibly renewed waiting for a request */
            /* to establish a connection */
            printf("End of program: An error occurred during connection 
            setup\n");
            break;
           }
       }
    } while (TRUE);
 exit(0);
}