Fundamentals 20 min read

How to Keep TCP Connections Alive: Heartbeat, Retransmission, and Timeout Techniques

This article explains how unstable network conditions cause TCP disconnections in video conferencing, then details TCP/IP heartbeat mechanisms, ACK handling, keepalive parameter tuning, libwebsockets integration, packet loss retransmission, and non‑blocking socket connect timeout control with code examples.

Open Source Linux
Open Source Linux
Open Source Linux
How to Keep TCP Connections Alive: Heartbeat, Retransmission, and Timeout Techniques

Problem Overview

In a project with an unstable client network, occasional packet loss and jitter cause the software client to lose its TCP connection to the server, interrupting ongoing video conferences. The customer requires the meeting to remain active for at least 60 seconds after network recovery.

TCP/IP Heartbeat Mechanism

TCP ACK Mechanism

TCP establishes a reliable connection through a three‑way handshake and acknowledges every received segment. If an ACK is not received, the sender triggers the packet‑loss retransmission mechanism.

Default TCP Keepalive

Windows enables a default keepalive packet every two hours. If the network is normal, the server replies with an ACK; the timer resets on any data exchange. If the network is abnormal, the client resends the keepalive after one second, up to ten attempts, after which the stack closes the connection.

Modifying Keepalive Parameters

Keepalive is enabled per socket using setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ...). The timing parameters are changed with WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, ...) where alive.keepalivetime (default two hours) and alive.keepaliveinterval (default one second) can be set.

SOCKET socket;<br/>int optval = 1;<br/>setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&optval, sizeof(optval));<br/><br/>tcp_keepalive alive;<br/>alive.onoff = TRUE;<br/>alive.keepalivetime = 10*1000;      // 10 seconds<br/>alive.keepaliveinterval = 2*1000;   // 2 seconds<br/>WSAIoctl(socket, SIO_KEEPALIVE_VALS, &alive, sizeof(alive), NULL, 0, &dwBytesRet, NULL, NULL);

The keepalivetime defines the interval between keepalive probes, while keepaliveinterval is the timeout waiting for an ACK. After ten unanswered probes, Windows reports WSAENETRESET and the socket is considered disconnected.

libwebsockets Heartbeat Integration

When using libwebsockets, the same TCP keepalive mechanism is applied. The context creation structure lws_context_creation_info contains fields ka_time, ka_interval, and ka_probes to configure keepalive.

static lws_context* CreateContext(){<br/>    lws_set_log_level(0xFF, NULL);<br/>    lws_context_creation_info info = {0};<br/>    info.port = CONTEXT_PORT_NO_LISTEN;<br/>    info.protocols = protocols;<br/>    info.ka_time = LWS_TCP_KEEPALIVE_TIME;<br/>    info.ka_interval = LWS_TCP_KEEPALIVE_INTERVAL;<br/>    info.ka_probes = LWS_TCP_KEEPALIVE_PROBES;<br/>    info.options = LWS_SERVER_OPTION_DISABLE_IPV6;<br/>    return lws_create_context(&info);<br/>}

During socket initialization, libwebsockets enables keepalive with setsockopt and configures the tcp_keepalive structure via WSAIoctl, then disables Nagle’s algorithm and sets the socket to non‑blocking mode.

int optval = 1;<br/>setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&optval, sizeof(optval));<br/>alive.onoff = TRUE;<br/>alive.keepalivetime = vhost->ka_time*1000;<br/>alive.keepaliveinterval = vhost->ka_interval*1000;<br/>WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive), NULL, 0, &dwBytesRet, NULL, NULL);

TCP Packet‑Loss Retransmission

If a data packet is sent but its ACK is not received due to network failure, TCP automatically retransmits the packet with exponential back‑off. After a platform‑specific maximum (Windows: 5 attempts, Linux: 15 attempts), the stack declares the connection broken and closes it.

Non‑Blocking Connect with Timeout Using select()

For a non‑blocking socket, connect() returns immediately with SOCKET_ERROR and WSAEWOULDBLOCK. The select() function can then monitor the socket for writability within a specified timeout. If the socket becomes writable, the connection succeeded; otherwise, it is considered failed.

bool ConnectDevice(char* ip, int port){<br/>    SOCKET s = socket(AF_INET, SOCK_STREAM, 0);<br/>    if(s == INVALID_SOCKET) return false;<br/>    SOCKADDR_IN addr = {0};<br/>    addr.sin_family = AF_INET;<br/>    addr.sin_port = htons(port);<br/>    addr.sin_addr.s_addr = inet_addr(ip);<br/>    unsigned long nb = 1;<br/>    ioctlsocket(s, FIONBIO, &nb);<br/>    connect(s, (sockaddr*)&addr, sizeof(addr));<br/>    fd_set wf;<br/>    FD_ZERO(&wf); FD_SET(s, &wf);<br/>    timeval tv = {1, 0}; // 1‑second timeout<br/>    if(select(0, NULL, &wf, NULL, &tv) <= 0){<br/>        closesocket(s); return false;<br/>    }<br/>    nb = 0; ioctlsocket(s, FIONBIO, &nb);<br/>    closesocket(s); return true;<br/>}

By using this pattern, the application can detect connection failures within a configurable period instead of waiting for the default blocking timeout (up to 75 seconds on Windows).

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

TCPWindowsNetwork programmingSocketC++Keepalive
Open Source Linux
Written by

Open Source Linux

Focused on sharing Linux/Unix content, covering fundamentals, system development, network programming, automation/operations, cloud computing, and related professional knowledge.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.