views:

355

answers:

3

I am currently using the BSD sockets API. I would like to use the select() function to monitor (a) the listener socket which waits for new connections using accept(), and (b) all the client sockets created via accept() or connect(). I want the listener socket to not have any timeout, and I want each client socket to have a timeout of 120 seconds.

Is this possible using the select() function? It only accepts a single timeout value for all sockets, so my assumption is no. If so, am I doomed to making a server in which each socket runs in blocking mode in its own thread?

A: 

Due to the logic of select() function, you should pass it minimal timeout of your ones. If this minimal timeout is hit, then the corresponding socket is timeouted and you should handle this situation. In other words, sockets with greater timeouts can never timeout, because they just wont' have chance to: the time is calculated starting from the last select() call, not the first one.

Go for threads; you can't do this with a single select().

Pavel Shved
Okay, running them in blocking mode in their own threads is actually how I already have it, and it actually works fine, but I was lead to believe that this wasn't "best practice." If it's the only way to do what I want, then I'll leave it the way it is.
oskar
A: 

You need to keep track of the remaining timeouts yourself, and pass the minimum timeout to select().

For example, suppose you want no timeout on the listening socket and a timeout of 10 minutes (timeout = 600 seconds) for each connection. For each connection, keep track of the time of the last activity on that socket in seconds, like this:

socket  last activity
  1        1950
  2        1990
  3        1500
  4        1998

The remaining timeout for each socket can then be calculated as last + timeout - curtime, so if the current time is 2000 (seconds), the remaining timeout for each connection is 550, 590, 100, and 598 respectively. The minimum of those is 100 so that is the next time that you will have a timeout condition in the absence of other activity, so pass that to the select() function. If the select() timeout expires then when you recalculate the remaining timeout on each socket you will find which socket(s) have timed out.

mark4o
Note that this sort of arithmetic is much easier if you keep all your time values as 64-bit integers, and only convert to "struct timeval" format as a final step just before passing the timeval struct to select().
Jeremy Friesner
+2  A: 

And why not do a design of this decade and use libevent?

piotr