linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Simulator
  • Knowledge base
  • Interview prep
Index
Categories
All entries
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
home/linux/kb/Networking: L4 and above/websocket

kb/network-l4 ── Networking: L4 and above ── intermediate

WebSocket: Bidirectional Channel over HTTP

WebSocket is a bidirectional channel over a single TCP connection. The upgrade from HTTP/1.1 uses the Upgrade header; after that, both sides exchange binary frames. Typical use cases: real-time UI, chats, dashboards, live updates.

view as markdownaka: websockets, ws-protocol, websocket-upgrade

Why WebSocket

HTTP is request/response: the server cannot push an update on its own. Before WebSocket, developers used polling (a request every 5 seconds) or long-polling. Both waste CPU and connections. WebSocket gives you one TCP connection through which both the client and the server send messages whenever they like.

LinuxLab uses WebSocket at /api/ws/sessions/{id} for the PTY terminal and state updates from the agent inside the container.

Handshake

It starts as a normal [[http-protocol|HTTP/1.1]] request with an upgrade:

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

The server replies with 101 Switching Protocols:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Sec-WebSocket-Accept = base64(SHA1(client_key + magic_GUID)). This is not a security mechanism. It protects against accidental upgrades by intermediaries that do not understand WebSocket.

After 101, the same TCP socket carries the traffic, but the protocol has changed: binary WebSocket frames flow from this point, not HTTP.

Frame format

 0   1   2   3   4   5   6   7
+-+-+-+-+---+---+-+-+---+---+----+
|F|R|R|R| op|M| payload-len  |...|
|I|S|S|S|cod|A|              |   |
|N|V|V|V|e  |S|              |   |
| |1|2|3|   |K|              |   |
+-+-+-+-+---+-+-+--------------+
  • FIN - is this the last frame in a logical message? (messages can be fragmented)
  • opcode - 0x1 text, 0x2 binary, 0x8 close, 0x9 ping, 0xA pong
  • MASK - client to server must mask the payload with XOR; server to client does not mask
  • payload-len - 7 / 16 / 64 bits (extended when length exceeds 125)

Masking from the client protects against cache-poisoning of old HTTP proxies.

ws:// vs wss://

  • ws:// - plain TCP, port 80
  • wss:// - TLS-wrapped, port 443

In production, always use wss://. The WebSocket handshake lives inside a [[tls-handshake|TLS session]]: it looks like an HTTPS request, and the upgrade happens inside the encrypted channel.

Ping / Pong

To confirm the connection is alive (NAT not closed, peer not down), either side sends a ping frame (opcode 0x9). The receiver must return a pong (0xA) with the same payload. If pong does not arrive within N seconds, the connection is considered dead and a reconnect is needed.

Typical interval: 30-60 seconds (shorter than the NAT timeout, which is usually 5 minutes for UDP NAT and 2 hours for TCP NAT).

Close

A clean shutdown uses a close frame (0x8) with a 2-byte status code:

CodeMeaning
1000normal closure
1001going away (page closed)
1002protocol error
1003unsupported data
1006abnormal closure (never sent explicitly; means the connection was dropped)
1011server error
4000+application-defined

A well-written client responds to 1006 with exponential backoff reconnect.

Backpressure

WebSocket has no native flow control at the message level (only the TCP window). If the server sends faster than the client can consume, the buffer grows. Under heavy load you need either application-level backpressure (acks from the client) or a drop-message policy.

Message size

Technically up to 2^63 bytes. In practice, servers enforce a limit of 1-16 MB. Send large files over HTTP, not over WebSocket.

When things go wrong

  • Connection closed before handshake - the reverse proxy did not forward the Upgrade header. In nginx you need proxy_set_header Upgrade $http_upgrade;
  • 1006 every 60 seconds - the load balancer closes idle connections. Add a ping or increase the LB timeout
  • Stuck after 1 message - the client forgot to mask; the server dropped the frame
  • Memory growth - no backpressure; slow clients accumulate buffer
  • Echo back to server - missing Origin header validation; cross-site WebSocket hijacking

§ команды

bash
curl -i -N -H 'Connection: Upgrade' -H 'Upgrade: websocket' -H 'Sec-WebSocket-Version: 13' -H 'Sec-WebSocket-Key: dGVzdA==' http://localhost:8080/ws

Perform a minimal WebSocket handshake by hand and see the 101 response.

bash
tcpdump -i any -nn -A 'tcp port 80' | grep -A2 -i 'upgrade'

Capture a WebSocket upgrade in plain text. With wss:// this requires a MITM setup.

bash
ss -tnH | grep ':443' | wc -l

Count active TLS connections currently open, including wss:// sessions.

bash
wscat -c wss://echo.websocket.org

A simple WebSocket client in the shell (npm i -g wscat). Send a message and get it echoed back.

§ см. также

  • http-protocolHTTP/1.1, HTTP/2, HTTP/3HTTP/1.1 is a text-based protocol with keep-alive. HTTP/2 is binary with multiplexing over a single TCP connection. HTTP/3 carries HTTP/2 semantics over QUIC/UDP without TCP head-of-line blocking.
  • tcp-handshakeTCP three-way handshakeTCP connection opens with three packets: SYN from the client, SYN-ACK from the server, ACK from the client. After that the connection is Established and data transfer can begin.
  • tls-handshakeTLS HandshakeTLS is the encryption layer above TCP. Before data flows, both sides run a handshake: they exchange keys, verify the certificate, and agree on a cipher.
  • portPort: How Multiple Services Share One IPA 16-bit number (0-65535) that identifies the **destination process** on a host. IP says which host; port says which process. 80 is HTTP, 443 is HTTPS, 22 is SSH.
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies