Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

blocking select() from multiple sockets

Unix/C question here.

I have multiple sockets that I am trying to poll for periodic data. I don't want select to wait indefinitely so I have a timeout in place and I'm running in a loop. I have found that once a socket is ready to read, it is always ready to read. As in, I cannot have select go to sleep when there is no data to be read from any of the sockets.

for (i = 0; i < n_connections; i++) {
  FD_SET( sockfd[i], &master );
  if (sockfd[i] > fdmax) 
    fdmax = sockfd[i];
  }

for(;;) {
  int nready = 0;
  timeout.tv_sec  = 1;
  timeout.tv_usec = 0;
  read_fds = master;
  if ( (nready = select(fdmax+1, &read_fds, NULL, NULL, NULL)) == -1 ) {
    fprintf( stderr, "Select Error\n" );
    return FAILURE;
  }
  printf( "Number of ready descriptors: %d\n", nready );

  for (i = 0; i <= fdmax; i++) {
    if (FD_ISSET(i, &read_fds)) {
      if (( nbytes = recv(i, buf, sizeof(buf), 0)) <= 0 ) {
        if (nbytes == 0) {
          //connection closed
          printf("Socket %d hung up\n", i );
        }
        else {
          fprintf( stderr, "Recv Error %d\n", nbytes);
        }
      }
    else {
      printf( "Data Received on %d: %s\n", i, buf );
    }
  }
} // end file descriptor loop

It seems that after my first read, the 1 second timeout no longer applies and the socket is always "ready to read", even if there are 0 bytes available. How can I get select to sleep until data comes in (for the one second, or by switching the final argument to NULL, indefinitely waiting for data to come in on the socket?)

Output:

Number of Ready Descriptors: 2
Data Received on 4: GreetingsChap
Data Received on 5: HiMatengsChap
Loop...
Number of Ready Descriptors: 2
Socket 4 hung up
Socket 5 hung up
Loop...
Number of Ready Descriptors: 2
Socket 4 hung up
Socket 5 hung up
Loop...

Thank you,

Note: Code updated for clarity Updated based on @yvesBraumes suggestions - still doesn't work.

like image 524
RootsAmongRuins Avatar asked Mar 05 '12 21:03

RootsAmongRuins


People also ask

Is select () blocking?

By using the select() call, you do not issue a blocking call until you know that the call cannot block. The select() call can itself be blocking, nonblocking, or, for the macro API, asynchronous.

Is listen () a blocking call?

listen() is non-blocking.

How many sockets can select handle?

The first argument is the highest file descriptor plus one. Thus, if we pass two file descriptors with values 2 and 10, then the nfds parameter should be 10 + 1 or 11 and not 2. The maximum number of sockets supported by select() has an upper limit, represented by FD_SETSIZE (typically 1024).

How do I use select with sockets?

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.


2 Answers

If you detect that a connection is closed, remove the socket from the fd set, otherwise select is going to report them (Socket 4 hung up).. select is not edge triggered, if you don't handle the event, it's going to report it again.

like image 68
Karoly Horvath Avatar answered Sep 18 '22 23:09

Karoly Horvath


Indeed, if recv returns 0 (and not -1, with errno=EWOULDBLOCK), the socket is closed. You should call close() on it as well, and take it out of the select() call. Otherwise it will remain in WAIT1 and release select() each time.

like image 28
lundman Avatar answered Sep 17 '22 23:09

lundman