TCPKeepAlive and KeepAliveTimeout for IOCP and EPOLL Servers | eSeGeCe Blog

TCPKeepAlive and KeepAliveTimeout for IOCP and EPOLL Servers

· Components
sgcWebSockets TCPKeepAlive and KeepAliveTimeout for IOCP and EPOLL

The IOCP (Windows) and EPOLL (Linux) server engines in sgcWebSockets handle thousands of connections with a small pool of threads instead of one thread per connection, which is what makes them the right choice for servers under heavy concurrent load. Until now, though, they had no way to notice a peer that goes quiet without saying goodbye. Two new options, TCPKeepAlive and KeepAliveTimeout, close that gap.

A Silent Peer Never Produces an Event

IOCP and EPOLL are event-driven: the engine sleeps until the operating system tells it a socket has data, has closed, or has errored. That works well right up until a peer disappears without sending a clean FIN or RST, for example a client that crashes, a NAT or firewall that drops an idle mapping, or a route that silently changes. No event ever arrives for that socket, so the connection stays ESTABLISHED on the server indefinitely.

The classic thread-per-connection IOHandler does not have this problem, because each connection blocks on a read with a timeout, so a silent connection is noticed and freed the next time that read times out. IOCP and EPOLL had no equivalent mechanism, which is exactly what these two new options add.

TCPKeepAlive: Let the Operating System Watch

Enable TCPKeepAlive and the operating system itself starts probing a connection once it has been idle for Time seconds, repeating every Interval seconds until the peer answers or the connection is dropped. It is off by default; the values below match the defaults when enabled.

Server.IOHandlerOptions.IOHandlerType := iohEPOLL;
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Enabled  := True;
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Time     := 60;  // seconds idle before probing
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Interval := 10;  // seconds between probes

On a Windows server, the same three properties live under IOHandlerOptions.IOCP.TCPKeepAlive.

KeepAliveTimeout: An Application-Level Idle Timeout

KeepAliveTimeout takes a different, more direct approach: it closes any connection that has stayed idle longer than the given number of seconds, regardless of what the operating system's keepalive probes decide. It is the closest match to how the thread-per-connection IOHandler already frees a silent connection, it is disabled by default (a value of 0), and only truly idle connections are affected, a request being read or a response being written is never interrupted by it.

Server.IOHandlerOptions.EPOLL.KeepAliveTimeout := 120; // seconds

// Windows
Server.IOHandlerOptions.IOCP.KeepAliveTimeout := 120;

Set it comfortably above your slowest expected request or response, for example 120 seconds for a typical HTTP or WebSocket server, so genuinely dead connections are reaped quickly without ever touching one that is just slow.

A Third Way to Detect a Disconnection

sgcWebSockets already offered two ways to notice that a peer is gone: enabling CleanDisconnect on TsgcWebSocketClient, so a well-behaved client tells the server before it goes away, or running a server-side heartbeat that pings every client on an interval. Both depend on cooperation, from the client in the first case, from your own ping/pong round trip in the second. TCPKeepAlive and KeepAliveTimeout are the first option that needs none of that: the server detects a dead connection entirely on its own.

Availability

Both options are available now in sgcWebSockets for Delphi and C++ Builder 7 through 13, under IOHandlerOptions.EPOLL and IOHandlerOptions.IOCP, next to the existing EPOLLThreads, IOCPThreads and WorkOpThreads settings. They are off by default, so nothing changes for existing servers unless you turn them on.

Download the trial and read the full IOCP and EPOLL reference on the sgcWebSockets product page.

Questions or feedback? Get in touch, you will get a reply from the people who wrote the code.