Search code examples
csocketsposix-select

c - Multiple select()s to monitor multiple FD_SETs


I'm not an expert in Network Programming. I basically have two kinds of clients who have different time-outs. I am supposed to use UDP with connected sockets for client-server communication.

The problem is twofold:

a) I need to mark as died whichever client (alternatively, socket) does not respond for t1 seconds. Using select would time out if none of the sockets in read_fd_set have anything to read within the timeout value. So, how do I time-out any one socket which is not having data to read for quite some time?

  • Currently, whenever select returns, I myself keep track of which sockets are responding and which not. And I add t1.tu_sec to the individual time elapsed of each client (socket). Then, I manually close and exclude from FD_SET the socket which does not respond for (n) * (t1.tu_sec) time. Is this a good enough approach?

b) The main problem is that there are two kinds of clients which have different time-outs, t1 and t2. How do I handle this?

  • Can I have two select()s for the two kinds of clients in the same loop? Would it cause starvation without threads? Is using threads advisable (or even required) in this case?

I've been roaming around the web for ages!

Any help is much appreciated.


Solution

  • This is just a special case of a very common pattern, where a select/poll loop is associated with a collection of timers.

    You can use a priority queue of tasks, ordered on next (absolute) firing time; the select timeout is always then just the absolute time at the front of the queue.

    • when select times out (and just before the next iteration, if your tasks may take a long time to complete), get the current time, pull every task that should already have executed off the queue, and execute it
    • (some) tasks will need to be re-scheduled, so make sure they can mutate the priority queue while you do this

    Then your logic is trivial:

    • on read, mark the socket busy
    • on timer execution, mark the socket idle
      • if it was already idle, that means nothing was received since the last timer expiry: it's dead