Learn WebSocket - Handshake & Connection Lifecycle
Episode 3 of 34

Learn WebSocket - Handshake & Connection Lifecycle

This episode dissects how a WebSocket connection is born and dies: handshake headers, the Sec-WebSocket-Accept calculation, the four connection states, frame structure, as well as the close frame and heartbeat mechanisms.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Every WebSocket connection begins with something ordinary: an HTTP request. Episode 3 dissects those early moments — the opening handshake — then follows the connection's journey through to its closure.

You will understand why the handshake is required, how the server proves it understands the WebSocket protocol, the four states a connection passes through, the anatomy of the frames that carry data, and the ping and pong mechanisms that keep the connection alive. These are the details that make your WebSocket application behave correctly in production.

The Opening Handshake

The Upgrade Request from the Client

When a browser or client opens a WebSocket connection, the first thing sent is an HTTP request with special headers. Look at these headers:

Handshake request from the client
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

The Upgrade: websocket header tells the server that the client wants to switch protocols, and Sec-WebSocket-Key is a random nonce the server will use to prove its understanding of RFC 6455.

The 101 Switching Protocols Response

If the server accepts, it returns:

Handshake response from the server
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Status 101 Switching Protocols signals that the connection is switching from HTTP to WebSocket. The key to this process lies in the Sec-WebSocket-Accept header: its value is not arbitrary, but the result of a calculation performed on the Sec-WebSocket-Key.

The Sec-WebSocket-Accept Calculation

The server combines the received key with a standard GUID, then hashes it:

JSSec-WebSocket-Accept calculation
const crypto = require("crypto");
 
function buatAccept(key) {
  const GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
  const hash = crypto.createHash("sha1").update(key + GUID).digest("base64");
  return hash;
}
 
const accept = buatAccept("dGhlIHNhbXBsZSBub25jZQ==");
console.log(accept);

The crypto.createHash("sha1") formula proves that the server truly understands the protocol. If the client does not receive the matching Sec-WebSocket-Accept, the connection is considered failed.

Protocol and Extension Negotiation

Two optional headers can also take part in the handshake:

  • Sec-WebSocket-Protocol: the list of subprotocols requested by the client, from which the server picks one.
  • Sec-WebSocket-Extensions: for example permessage-deflate for message compression.

Connection States

The Four Official States

WebSocket defines four connection states. In the browser, you read them through the readyState property:

  • CONNECTING (0): the handshake is in progress.
  • OPEN (1): the connection is ready for message exchange.
  • CLOSING (2): the closing process is under way.
  • CLOSED (3): the connection has ended and can no longer be used.
JSReading the connection state
const ws = new WebSocket("ws://localhost:8080");
 
console.log(ws.readyState); // 0 = CONNECTING
 
ws.onopen = () => {
  console.log(ws.readyState); // 1 = OPEN
};

new WebSocket("ws://localhost:8080") automatically opens the handshake right away. Notice the state transitions: from 0 to 1 after onopen, and toward 2 then 3 when the closure begins.

Frame Structure

The Anatomy of a Frame

After the handshake, all data is sent in frames. Each frame begins with a small header containing:

  • FIN: marks the final frame of a message.
  • RSV: reserved bits, used for extensions such as compression.
  • opcode: the frame type — text, binary, close, ping, or pong.
  • MASK: a flag that the payload is masked (mandatory for client-to-server).
  • Payload length: the data length, 7-bit, 16-bit, or 64-bit.

Masking Rules

An important rule in RFC 6455: all client-to-server frames must be masked, while server-to-client frames are not. Masking prevents cache poisoning on legacy proxies that misinterpret frames.

Connection Lifecycle and Heartbeat

The Connection Lifecycle

A single WebSocket connection goes through these phases:

  1. Establishment: the handshake succeeds, the state becomes OPEN.
  2. Message exchange: the exchange of text or binary frames.
  3. Heartbeat: ping and pong keep the connection alive through proxies.
  4. Closure: a close frame is sent, the state becomes CLOSED.

The Close Frame

Closure is not a casual disconnect. One side sends a close frame with a code and reason:

JSClosing the connection with a code
ws.close(1000, "selesai");

Code 1000 means a normal closure. Other common codes: 1001 going away, 1006 abnormal connection without a close frame, and 1009 message too big. Using ws.close(1000, "selesai") with a clear reason helps debugging in production.

Heartbeat with Ping and Pong

Because a connection can stay idle for too long, the server routinely sends ping and the client must reply with pong. This is early detection of dead connections that in a later episode we will build into a complete heartbeat system with timeouts.

Tip

Do not rely on TCP timeouts alone. Many proxies and load balancers drop idle connections after a few minutes. Regular ping/pong keeps the connection looking active and prevents silent disconnects.

Closing

Episode 3 dissected the mechanics behind every WebSocket connection: the upgraded HTTP handshake, the Sec-WebSocket-Accept calculation, the four connection states, the frame structure with masking rules, the close frame, and the ping/pong heartbeat.

Key takeaways:

  • A WebSocket connection is born from an HTTP request with the Upgrade header.
  • The server proves its protocol understanding via Sec-WebSocket-Accept.
  • The connection passes through the CONNECTING, OPEN, CLOSING, and CLOSED states.
  • Frames carry an opcode, mask, and payload length.
  • Clients must mask their frames; servers do not.
  • Ping and pong keep the connection alive and detect dead connections.

In the next episode we will come up to the surface: the native WebSocket API in the browser — creating a WebSocket instance, the four event handlers, the send and close methods, and the readyState and bufferedAmount properties. You will start writing real client code.

Learn WebSocket - Handshake & Connection Lifecycle | Learn WebSocket