Working with Ping and Pong Frames

1. Understanding Ping/Pong Mechanism

FrameOpcodePurpose
Ping0x9Liveness probe
Pong0xAAuto/explicit response
Payload≤ 125 bytesOptional correlation token
Warning: The browser WebSocket API cannot send/observe ping/pong frames — they're auto-handled. Use server-initiated ping or application-level heartbeat.

2. Sending Ping Frames

Example: Node ws server ping

import { WebSocketServer } from "ws";
const wss = new WebSocketServer({ port: 8080 });
setInterval(() => {
  for (const c of wss.clients) {
    if (c.isAlive === false) return c.terminate();
    c.isAlive = false;
    c.ping();
  }
}, 30000);
MethodDetail
ws.ping(data, mask, cb)Send ping
ws.pong(data)Explicit pong
Auto-pongws library responds automatically

3. Handling Pong Responses

Example: Mark alive on pong

wss.on("connection", (c) => {
  c.isAlive = true;
  c.on("pong", () => { c.isAlive = true; });
});
EventUse
"pong"Mark client alive
"ping"Optional logging

4. Implementing Heartbeat

Example: App-level heartbeat (browser)

let hb;
ws.addEventListener("open", () => {
  hb = setInterval(() => ws.send(JSON.stringify({ "type": "ping" })), 25000);
});
ws.addEventListener("close", () => clearInterval(hb));
IntervalUse Case
5-15sAggressive (mobile, NAT)
25-30sStandard
55sJust under LB idle timeout (60s)

5. Detecting Stale Connections

SignalThreshold
No pong in 2 intervalsMark dead
No traffic 60sProbe
bufferedAmount stuckSlow / dead

6. Closing Dead Connections

Example: Forced terminate

if (c.isAlive === false) c.terminate(); // skip close handshake
MethodEffect
close(code,reason)Sends close frame
terminate() (ws)Immediate TCP teardown

7. Customizing Ping Interval

FactorTune For
LB idle timeoutPing ≤ 80% of timeout
Mobile batteryLonger intervals when hidden
Latency-criticalShorter for fast dead-detect

8. Handling Client Ping

SourceBehavior
BrowserCannot send protocol pings
Node clientws.ping() supported
ServerAuto-pongs any client ping

9. Monitoring Connection Health

MetricUse
Heartbeat RTTLatency trend
Missed pongsDisconnect predictor
Reconnect rateNetwork quality
Buffered bytesBackpressure

10. Implementing Custom Heartbeat Protocol

Example: Ping with RTT

const sent = new Map();
function ping() {
  const id = crypto.randomUUID();
  sent.set(id, performance.now());
  ws.send(JSON.stringify({ "type": "ping", "id": id }));
}
function onPong({ id }) {
  const rtt = performance.now() - sent.get(id);
  sent.delete(id);
  metrics.observe("rtt_ms", rtt);
}
FieldUse
idMatch ping↔pong
tsOne-way delay estimate
seqDetect missed