How to Keep TCP Connections Alive: Heartbeat, Retransmission, and Timeout Techniques
This article explains how unstable network conditions cause TCP disconnections in video conferencing, and provides detailed guidance on TCP/IP heartbeat mechanisms, packet loss retransmission, socket keep‑alive configuration, libwebsockets integration, and non‑blocking connect timeout control with code examples.
1. Problem Overview
The client’s network is unstable, causing packet loss and jitter that break the TCP connection to the server, interrupting ongoing video conferences. The requirement is to keep the meeting alive for 60 seconds after network recovery.
2. TCP/IP Heartbeat Mechanism
2.1 ACK Mechanism
TCP establishes a reliable connection using a three‑way handshake and acknowledges every received segment with an ACK packet. If an ACK is not received, the sender triggers packet retransmission.
2.2 TCP/IP Heartbeat Description
Windows disables the socket keep‑alive by default. When enabled, the system sends a heartbeat packet every keepalivetime (default 2 hours). If the server replies with an ACK, the timer resets. If no ACK is received, the system retries every keepaliveinterval (default 1 second) up to probe times (default 10). After the limit, the connection is considered broken and is closed.
2.3 Modifying Default Heartbeat Parameters
To change the parameters, enable keep‑alive with setsockopt and then adjust the values using WSAIoctl:
SOCKET socket;<br/>int optval = 1;<br/>int nRet = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&optval, sizeof(optval));<br/>if (nRet != 0) return;<br/><br/>tcp_keepalive alive;<br/>alive.onoff = TRUE;<br/>alive.keepalivetime = 10*1000; // 10 seconds<br/>alive.keepaliveinterval = 2*1000; // 2 seconds<br/><br/>DWORD dwBytesRet = 0;<br/>nRet = WSAIoctl(socket, SIO_KEEPALIVE_VALS, &alive, sizeof(alive), NULL, 0, &dwBytesRet, NULL, NULL);<br/>if (nRet != 0) return;The tcp_keepalive structure fields are:
keepalivetime : interval between heartbeat packets (default 2 hours).
keepaliveinterval : timeout waiting for an ACK (default 1 second).
probe : number of unanswered heartbeats before the stack drops the connection (fixed at 10 on Windows).
3. libwebsockets Heartbeat Usage
WebSocket long connections can be closed by intermediate network devices when idle. libwebsockets provides keep‑alive settings via the lws_context_creation_info structure ( ka_time, ka_interval, ka_probes).
static lws_context* CreateContext(){<br/> lws_set_log_level(0xFF, NULL);<br/> lws_context_creation_info info;<br/> memset(&info, 0, sizeof(info));<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/>}The underlying implementation also uses the OS TCP keep‑alive mechanism:
int optval = 1;<br/>setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&optval, sizeof(optval));<br/>tcp_keepalive alive;<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);4. TCP/IP Packet Loss Retransmission
If a data packet is sent but its ACK is not received, TCP retransmits the packet with exponential back‑off. After a platform‑specific maximum number of retries (Windows 5, Linux 15), the stack declares the network faulty and closes the connection.
5. Non‑Blocking Socket Connect Timeout
5.1 MSDN Description of connect and select
For a non‑blocking socket, connect returns SOCKET_ERROR and WSAEWOULDBLOCK. The connection’s completion must be detected with select on the write set.
5.2 Implementing Connect Timeout
Set the socket to non‑blocking, call connect, then use select with a timeout (e.g., 1 second). If select indicates writability, the connection succeeded; otherwise, close the socket.
bool ConnectDevice(char* pszIP, int nPort){<br/> SOCKET connSock = socket(AF_INET, SOCK_STREAM, 0);<br/> if (connSock == INVALID_SOCKET) return false;<br/> SOCKADDR_IN devAddr = {0};<br/> devAddr.sin_family = AF_INET;<br/> devAddr.sin_port = htons(nPort);<br/> devAddr.sin_addr.s_addr = inet_addr(pszIP);<br/> unsigned long ulnoblock = 1;<br/> ioctlsocket(connSock, FIONBIO, &ulnoblock);<br/> connect(connSock, (sockaddr*)&devAddr, sizeof(devAddr));<br/> fd_set writefds; FD_ZERO(&writefds); FD_SET(connSock, &writefds);<br/> timeval tv = {1, 0}; // 1 second timeout<br/> if (select(0, NULL, &writefds, NULL, &tv) <= 0){<br/> closesocket(connSock); return false;<br/> }<br/> ulnoblock = 0; ioctlsocket(connSock, FIONBIO, &ulnoblock);<br/> closesocket(connSock); return true;<br/>}Images
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Linux
Focused on sharing Linux/Unix content, covering fundamentals, system development, network programming, automation/operations, cloud computing, and related professional knowledge.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
