Why does FD_ISSET return true after select()

29,040

The values stored in your fd_set do remain after select() fires. In an application it is possible for select() to monitor many sockets. Automatically cleaning the fd_set would mean you could never detect that multiple sockets need servicing.

You need to do your FD_ZERO() and FD_SET() inside the infinite loop so that on each pass the fd_set is initialized cleanly before select() is called.

Share:
29,040
Admin
Author by

Admin

Updated on July 05, 2022

Comments

  • Admin
    Admin almost 2 years

    I am new to sockets programming and I'm trying to thoroughly understand how it works, but for now I'm really stuck on select().

    The problem is that in my code, after select detects activity and the fd stays set, it seems that on next iterations FD_ISSET will return true automatically, like it would ignore the select function. The problem seems to be identical to this one, but I did all that I found there and to no avail: http://compgroups.net/comp.unix.programmer/how-does-fd_isset-return-0-after-returne/55058

    I made sure to reinitialize the timeval variable after select() since I'm on Linux and I understood this function behaves differently on different OSes, I also reinitialized the fd set with FD_ZERO and FD_SET before select.

    What am I doing wrong? Here is the code:

    #include <stdio.h>
    #include <strings.h>
    
    #include <sys/select.h>
    #include <sys/time.h>
    
    int main () {
      struct timeval tv;
    
      tv.tv_sec = 5; // 5 seconds timeout
      tv.tv_usec = 0;
    
      fd_set afds, rfds;
    
      FD_ZERO(&afds);
      FD_SET(0, &afds);
    
      while (1) {
        rfds = afds;
        select(1, &rfds, NULL, NULL, &tv);
        // linux, reinitialize tv?
        tv.tv_sec = 5;
        tv.tv_usec = 0;
    
        // so at this point after select runs the first time and detects STDIN activity
        // it will enter an infinite loop printing "fd 0 is set" (why?)
        if (FD_ISSET(0, &rfds)) {
          printf("fd 0 is set\n");
          FD_CLR(0, &rfds);
        } else {
          printf("fd 0 is NOT set\n");
        }
      }
    }
    

    Question edit since I'm a new user and can't answer this:

    The fact is I initialize rfds before select when it is assigned the value of afds, which in turn is always set with FD_ZERO(&afds); FD_SET(0, &afds); This still doesn't work for me.

    Here's what I understand:

    1. I add stdin file descriptor to afds

    2. Enter while infinite loop, rfds = afds (rfds will always be = afds at the start of the loop)

    3. Also, at this time, FD_ISSET(0, &rfds) will always be != 0

    4. select has a timeout of 5 seconds, so at this time if I don't type anything before the 5 seconds pass, it exits, UNSETTING FD_ISSET(0, &rfds) - is that correct? so select will actually unset the fd 0 if nothing is typed. This seems to work OK

    5. The problem arrives when I type something before the timeout. At this point, FD_ISSET(0, &rfds) returns != 0, it prints fd 0 is set, and then each loop fd will be set

    Ok, is this accurate, did I get it right? So practically select doesn't wait for the time to pass because it actually detects that the fd is ready and exits, setting the fd != 0 ?

    Which would beg for a further question: if I need the server to send automatically messages to several clients every once in a while (independently of what it reads from clients), would it be possible to do it with select and gettimeofday by adapting the code above?

    Thanks for the help.

  • RedSoft
    RedSoft almost 7 years
    You missed that FD_ZERO() and FD_SET() is done inside the loop by means of rfds = afds assignment