# The Importance of Heartbeat Detection in WebSocket Connections
Written on
Understanding Heartbeat Detection in WebSocket
WebSocket technology is widely utilized in web applications. A connection can easily be established using the WebSocket constructor available in browsers. However, in many specific implementations, heartbeat detection is typically included.
The primary goals of heartbeat detection are twofold: to ensure both communicating parties remain active and to enable the browser to quickly verify the current network connection's status. This facilitates timely message delivery.
You might wonder whether WebSocket is so elementary that it lacks a built-in connection status detection feature. To answer this, we first need to revisit some fundamental concepts of computer networking.
Overview of Network Protocols
At the core of the TCP/IP protocol suite is a four-layer model:
- Application Layer: This layer dictates how communication activities occur while providing services to users, with protocols like HTTP, FTP, and WebSocket functioning here.
- Transport Control Protocol (TCP) Layer: Responsible for managing data transmission between two hosts by segmenting data from the application layer (e.g., breaking down an HTTP message) and sending it to a designated port on the target host. Each segment is tagged with a source port, target port, and sequence number.
- Internet Protocol (IP) Layer: This layer maps IP addresses to MAC addresses and appends information such as source and target IPs to TCP packets, facilitating their journey across the network.
- Link Layer: Converts binary data packets to electrical signals for transmission over Ethernet cables, handling the sending and receiving of datagrams for the IP network layer.
TCP is a reliable, connection-oriented protocol. Once a handshake connection is established, the sender awaits confirmation from the receiver for each sent TCP message within a specified time frame. If no acknowledgment is received, the message is resent, ensuring all TCP messages are delivered and reassembled correctly at the application layer.
The WebSocket protocol can also be layered over TCP using TLS for secure communication.
Comparing WebSocket and HTTP
WebSocket functions similarly to HTTP as an application layer protocol that operates over TCP. When establishing a WebSocket connection, an existing HTTP GET request is utilized for the handshake. The client sends details about the WebSocket protocol version in the request headers, and upon acceptance, the server responds with a 101 status code. This transition allows a single HTTP request and response to switch to WebSocket seamlessly.
Unlike HTTP, where requests are client-initiated, WebSocket enables bidirectional communication. The server can proactively notify the client of new messages without waiting for the client to request them.
WebSocket is considered part of HTML5, while HTTP predates HTML5. Each WebSocket message (known as a data frame) is lighter than an HTTP message, containing only essential header information without cookies or custom headers. After a connection is established, interaction is one-to-one, without needing to send authentication data, although the initial handshake request will include cookies.
In terms of data management, WebSocket can divide large data sets into multiple frames, while HTTP processes each message as a single entity.
WebSocket vs. WebRTC: Key Differences
WebRTC, developed by Google, facilitates real-time communication between browsers, such as video calls, whereas WebSocket serves as a protocol abstraction enabling communication between browsers and servers.
Heartbeat Detection Mechanisms in Protocols
From research, WebSocket can employ two methods to check if the other party remains active:
- TCP KeepAlive Mechanism: Although primarily implemented on the server side, this feature periodically sends heartbeat messages to confirm the other party's status. Since this mechanism is tied to the TCP transport layer, its implementation varies by operating system. Consequently, the application layer receives connection status notifications from the operating system, resulting in uncertainty and varying response frequencies.
- WebSocket Keep-Alive: This requires both parties to implement it. WebSocket data frames include a 4-bit OPCODE that specifies the frame type, such as a close frame (0x8), ping frame (0x9), or pong frame (0xA).
The close data frame is sent when one party wishes to terminate the connection, while the ping frame is used to check if the other party is still active, acting as a heartbeat package. The backend controls ping transmission, and currently, no browser-side APIs are available to manage this.
Upon receiving a ping frame, the responding party must reply with a pong data frame to indicate its presence. This response mechanism is automatic in browsers but varies across different implementations, with no available JavaScript APIs to control it.
In summary, heartbeat detection is primarily initiated by the server in WebSocket communications, as browsers lack built-in capabilities to monitor backend connectivity in real-time. Thus, implementing heartbeat detection on the client side is essential for maintaining connection reliability.
The Necessity of Heartbeat Detection on the Client Side
To understand when a browser-side WebSocket connection will automatically close, consider the following scenarios:
- The WebSocket address is unreachable during the handshake.
- Unexpected errors arise.
- A close frame is received from the server, triggering the close callback.
Consequently, if the browser loses its network connection or the server closes the connection without a close frame, the connection status may remain active for an extended period. If the business logic does not actively check the connection, these issues may go unnoticed.
Furthermore, maintaining inactive connections consumes valuable server resources, which could be better allocated elsewhere.
Implementing Heartbeat Detection on the Frontend
To illustrate the implementation of a WebSocket connection with heartbeat detection, consider the following code snippet:
function connectWS() {
const WS = new WebSocket("ws://127.0.0.1:7070/ws/?name=greaclar");
WS.addEventListener('open', () => {
console.log('WebSocket connection established');});
WS.addEventListener('message', (event) => {
console.log('Message received via WebSocket', event.data);});
WS.addEventListener('close', () => {
console.log('WebSocket connection closed');});
WS.addEventListener('error', (error) => {
console.log('WebSocket error', error);});
return WS;
}
let WS = connectWS();
This snippet sets up a WebSocket connection in the frontend environment. The connection is established using the WebSocket constructor, with event listeners added to handle various connection events.
Heartbeat Detection Logic
To implement heartbeat detection, we need to define instance methods:
// Send a message to serve as a heartbeat
WS.send('hello');
// Close the connection if there is no response to the heartbeat
WS.close();
These commands are critical for enabling heartbeat functionality within the WebSocket connection. The WS.send('hello'); command sends a simple heartbeat message to check connectivity, while WS.close(); is used to terminate the connection if no response is received.
Logic for Sending Heartbeat Packages
To manage heartbeat detection, we need to track the current heartbeat status with three possible states: waiting, response received, and timeout.
- Monitor the message event for the WS instance, updating the heartbeat status upon receiving a response.
- Initiate heartbeat detection after a successful connection, starting with Timer A.
#### Timer Logic
When Timer A executes, the following occurs:
- The current heartbeat status is set to waiting.
- A heartbeat package is sent.
- Timer B is initiated.
Upon sending the heartbeat package, the backend should respond with a corresponding heartbeat response package, updating the heartbeat status to response received.
When Timer B executes, it checks the heartbeat status:
- If a response has been received, Timer A restarts, continuing the detection loop.
- If the status is still waiting, it indicates connection issues, prompting closure of the connection.
let WS = connectWS();
let heartbeatStatus = 'waiting';
WS.addEventListener('open', () => {
startHeartbeat();
});
WS.addEventListener('message', (event) => {
const { data } = event;
console.log('Heartbeat response received, updating status', data);
if (data === '"heartbeat"') {
heartbeatStatus = 'received';}
});
function startHeartbeat() {
setTimeout(() => {
heartbeatStatus = 'waiting';
WS.send('heartbeat');
waitHeartbeat();
}, 1500);
}
function waitHeartbeat() {
setTimeout(() => {
console.log('Checking server response, current status:', heartbeatStatus);
if (heartbeatStatus === 'waiting') {
WS.close();} else {
startHeartbeat();}
}, 1500);
}
Optimizing Heartbeat Detection
If heartbeat detection fails without triggering a close event, it may indicate a poor network connection. Immediate reconnection attempts could consume additional resources and hinder user actions.
To address this, it is prudent to delay and inform users of potential network issues, preparing them psychologically. After a brief wait, send one or two additional heartbeat packets. If no response is received, notify the user of the disconnection and ask if they wish to reconnect. If connectivity is restored in the interim, a reconnection is unnecessary, enhancing user experience and reducing server load.
#### Code Modifications
To enhance the existing code for retry logic:
let retryCount = 0;
WS.addEventListener('message', (event) => {
const { data } = event;
console.log('Heartbeat response received, updating status', data);
if (data === '"heartbeat"') {
retryCount = 0;
heartbeatStatus = 'received';
}
});
function waitHeartbeat() {
setTimeout(() => {
if (heartbeatStatus === 'received') {
return startHeartbeat();}
retryCount++;
if (retryCount < 3) {
alert('WS connection is abnormal, checking in progress.');
return startHeartbeat();
}
WS.close();
}, 1500);
}
This code modification introduces a retry counter to track consecutive non-responses and manages heartbeat detection more effectively.