WebSocket 1006, 101 and Ping/Pong Explained: The Words Before the Deep Dive

October 7, 2026 · How It Actually Works: Real Systems as State Machines (part 17)

▶ Watch on YouTube & subscribe to The Stack Underflow

101 Switching Protocols looks like an odd status code. It isn’t an error: it’s the last HTTP response on a WebSocket connection, and from then on the connection carries frames. This primer explains the WebSocket words, each with a memory peg, before the deep dive follows one WebSocket through Application Gateway, NGINX, Tomcat and Spring.

The one-line version: a WebSocket starts as an HTTP request and ends its HTTP life with one answer, 101. After that, everything is a frame, and a goodbye is a Close frame with a code. 1006 means no goodbye arrived.

Last verified against RFC 6455, the WHATWG WebSockets standard, nginx.org and NGINX’s source, the Spring reference, the STOMP 1.2 specification and Microsoft Learn: 6 October 2026. Scope: the classic HTTP/1.1 Upgrade path. Every claim links to its source at the bottom of the page.

How the pegs work

Every word gets a peg, a picture to hang it on. The pegs are memory aids, not how the protocol works.

The address: ws://, wss:// and where TLS ends

WordMemory pegWhat it actually is
ws:// vs wss://Postcard vs sealed envelopews is unencrypted, on port 80 by default. wss runs WebSocket over TLS, on port 443 by default, and TLS is what gives the connection confidentiality and integrity. The standard says implementations should use it.
TLS terminationThe mail roomWhere the envelope is opened. Application Gateway can end TLS, and so can NGINX. Behind that point, the next leg is a separate connection: often plain, or encrypted again with a new TLS session. So wss in the browser doesn’t mean TLS all the way to Tomcat.

The handshake: Upgrade, Connection and 101

A WebSocket starts as an ordinary HTTP request, and ends its HTTP life with one answer.

WordMemory pegWhat it actually is
Opening handshakeThe knockAn HTTP/1.1 GET asking the server to switch protocols. WebSocket over HTTP/2 or HTTP/3 bootstraps differently.
Upgrade and ConnectionA one-hop sticky noteThe request carries Upgrade: websocket and Connection: Upgrade. Both are hop-by-hop headers, so NGINX doesn’t pass them to the server behind it unless you set them explicitly, with proxy_set_header.
101 Switching ProtocolsThe door opensThe server completes the handshake with 101. It isn’t an error: it’s the last HTTP response on this connection, and from then on it carries WebSocket frames. With any other status, the browser fails the connection.
Sec-WebSocket-Key and Sec-WebSocket-AcceptChallenge and stamped replyThe browser sends a Sec-WebSocket-Key. The server appends a fixed GUID to it, hashes that with SHA-1, base64-encodes the result, and returns it as Sec-WebSocket-Accept. That proves the server received a WebSocket handshake, so the server doesn’t accept connections that aren’t WebSocket connections.

Frames: masking, ping/pong and heartbeats

After 101, everything is a frame.

WordMemory pegWhat it actually is
FrameLabelled parcels on a conveyor beltThe unit a WebSocket sends. Its opcode says what it is: text, binary, close, ping or pong, or a continuation of a message split across frames. The FIN bit marks the final fragment.
MaskingOnly the browser wears a maskA client, here the browser, must mask every frame it sends to the server, and the server must not mask its frames. Where the peg breaks: masking isn’t encryption. The masking key travels inside the frame. Masking stops a page’s script from choosing the exact bytes on the wire, which an intermediary could misread as an HTTP request. Encryption comes from TLS.
Ping / pongMarco… PoloA ping is a control frame, and whoever receives one must answer with a pong, unless it has already received a Close frame. A ping can work as a keepalive, or check that the other end still responds. The browser’s JavaScript API doesn’t expose ping and pong, though the browser itself may send them.
HeartbeatThe regular knockTraffic you send on purpose, so a quiet connection isn’t closed as idle: a server ping, a STOMP heart-beat, or an application message. By default, NGINX closes a proxied WebSocket that’s quiet for 60 seconds. A heartbeat only helps if it reaches the timer you’re fighting.

Goodbyes: close codes, 1006, and STOMP on top

WordMemory pegWhat it actually is
Close codeThe goodbye noteA clean goodbye is a Close frame with a code. 1000 is a normal closure. 1001 means going away, like a server going down or a browser leaving the page. 1011 means the server hit an unexpected condition. The other side answers with its own Close frame, typically echoing the code.
1006The slammed door, with no noteReserved: it must never be sent in a Close frame. The browser reports it when the connection closed without one: a dropped connection, a proxy timeout, or a handshake that failed. 1006 wasn’t sent by the server. It means no goodbye arrived.
STOMPThe sorting office on top of the lineA messaging protocol that Spring runs over WebSocket, for publish-subscribe messaging through a broker. STOMP declares heart-beats in a heart-beat header on its own CONNECT and CONNECTED messages, which travel inside WebSocket frames, and Spring’s simple broker supports them when it has a task scheduler.

The whole map

  • The address: the browser’s wss address, and the mail room where TLS ends.
  • The handshake: Upgrade and Connection, the key and its accept, and 101.
  • Frames: masked from the browser, pings and pongs, heartbeats.
  • The goodbye: a close code, or 1006 when none arrived, with STOMP riding on top.

Pause & Prove

1. The pinned question

Your WebSocket handshake gets back a 101. Is something wrong? And later the browser reports close code 1006: who sent it?

Nothing is wrong: 101 Switching Protocols completes the handshake. It’s the last HTTP response on the connection; from then on it carries WebSocket frames. And nobody sent the 1006: it’s reserved and must never be sent in a Close frame. The browser reports it when the connection closed without one.

2. The Community poll

Browser-to-server WebSocket frames are masked. Is masking a form of encryption?

  • Yes, that’s why it’s safe. The tempting one. Masking isn’t encryption; it stops a page’s script from choosing the exact bytes on the wire, which an intermediary could misread as an HTTP request.
  • No: the key is inside the frame. ✓ The masking key travels inside the frame itself. Encryption comes from TLS, with wss://.
  • Only on wss://. A client must mask every frame it sends to the server, on ws:// and wss:// alike. TLS is a separate layer.
  • Only from server to browser. The other way round: the browser masks; the server must not mask its frames.

3. Peg drill

Say the peg for each before reading on: wss, TLS termination, Upgrade, 101, masking, ping, heartbeat, 1006.

Answers: wss is a sealed envelope, and TLS termination is the mail room that opens it. Upgrade is a sticky note that lasts one hop. 101 is the door opening. Only the browser wears a mask. Ping and pong are Marco and Polo. A heartbeat is the regular knock. And 1006 is the slammed door, with no goodbye note.

Before / after this video

Sources

Read on 6 October 2026:

  • RFC 6455, The WebSocket Protocol: ws/wss and ports 80/443, TLS (§10.6, §11.1.2), the HTTP/1.1 GET with Upgrade and Connection (§4.1), 101, Sec-WebSocket-Accept from the key and the GUID (§1.3), opcodes and FIN (§5.2), masking (§5.1, §5.3, §10.3), ping and pong (§5.5.2), the Close handshake (§5.5.1), close codes 1000, 1001, 1011 and 1006 (§7.4.1, §7.1.5)
  • WHATWG WebSockets Standard: ping and pong “are not currently exposed in the API”, the browser may send them itself; a non-101 handshake fails the connection; the cases that report 1006
  • nginx.org, WebSocket proxying: hop-by-hop Upgrade and Connection must be passed explicitly; closed after 60 s without data by default
  • NGINX source, src/http/ngx_http_upstream.c: on an upgraded connection, traffic in either direction restarts the proxy_read_timeout clock
  • nginx.org, Configuring HTTPS servers: NGINX can end TLS
  • Microsoft Learn, Application Gateway overview and TLS termination: a layer 7 proxy that can end TLS and opens a separate backend connection
  • Spring Framework, WebSocket: STOMP as a sub-protocol over WebSocket for publish-subscribe messaging
  • Spring Framework, Simple broker: heartbeats when configured with a task scheduler
  • STOMP 1.2 specification, Heart-beating: the heart-beat header on CONNECT and CONNECTED
  • RFC 8441 (WebSocket over HTTP/2) and RFC 9220 (over HTTP/3): a different bootstrap

Change notes

  • 7 Oct 2026: first published.

Not affiliated with or endorsed by F5, the nginx project, the Apache Software Foundation or Microsoft. NGINX is a trademark of F5, Inc. Found a mistake? Tell us in the video’s comments and we’ll correct this page.

Found this useful? The deep version lives on YouTube — new breakdowns of how AI dev tools actually work, weekly.

Subscribe on YouTube →

Prefer email? Get the free newsletter: one failure, traced step by step, about once a week.