4

I am building a webserver which can accept and handle multiple client connections. I'm using select() for this.
Now while this is going on, if a particular connected socket hasn't had any activity (send or recv) on it, I want to close it. So if no requests come from a connected client for a period of time, I'll close the socket. There are multiple such connected sockets and I need to do this monitoring for each.

I need this functionality to create persistent connections as my webserver has to support HTTP 1.1

What is the best way to do this?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Raghav
  • 41
  • 3

2 Answers2

1

I'd suggest setting the timeout of the call to select to be the minimum time until the next socket will timeout. Then, if it timed out, close the idle sockets, and repeat. Something like this pseudocode:

timeout = default_timeout;
foreach(socket s)
{
    timeout = min(timeout, (s.last_send_or_recv_time + IDLE_TIMEOUT - now()));
}

result = select(..., timeout);
if(result == 0)
{
    foreach(socket s)
    {
        if(now() - s.last_send_or_recv_time >= IDLE_TIMEOUT)
        {
            close(s);
            remove_from_socket_list(s);
        }
    }
}
else
{
    // Handle received data, update last_send_or_recv_time, etc.
}
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
1

If you're using threads and blocking mode, you just need to set a suitable SO_RCVTIMEOUT on the socket and when you get read() returning -1 with errno == EAGAIN/EWOULDBLOCK, the timeout has happened, so you just close the socket and exit the thread.

If you're using select() it's more complicated. Adam Rosenfield's suggestion looks plausible on the surface, but in practice, if the other sockets are busy enough, the select() timeout might never happen at all, or at least not happen for many minutes after a socket actually became too dead. If you want to enforce the timeout strictly, as you should in a server, you have to associate a last-read time with each socket and, at the bottom of the select() loop, iterate over the fd set picking out those fds that were not ready, check their last-read time, and close the ones that are too dead.

user207421
  • 305,947
  • 44
  • 307
  • 483