Communication Protocols
The Network Stack
Every HTTPS request flows through three layers:
HTTP (application layer — your request/response)
TLS (security layer — encryption + authentication)
TCP (transport layer — reliable, ordered delivery)
TLS does two things during the handshake:
- Authentication — certificate verification against a trusted CA (is this really google.com?)
- Encryption — client and server agree on a shared key so all data is encrypted in transit (no ISP/WiFi snooping)
Full connection sequence: TCP handshake → TLS handshake → HTTP request/response
HTTP Versions
HTTP/1.1 — One Request at a Time
A single TCP connection handles requests sequentially — send request, wait for full response, then send the next one. This is head-of-line (HOL) blocking at the HTTP level.
GET /style.css → wait... ← response
GET /image1.png → wait... ← response
GET /image2.png → wait... ← response
Browser workaround: open ~6 parallel TCP connections per domain.
Domain sharding hack: serve resources from images1.example.com, images2.example.com to get 6 × N connections. Real optimization technique from the HTTP/1.1 era.
HTTP/2 — Multiplexing
One TCP connection carries multiple streams simultaneously. Data is broken into small frames tagged with a stream ID. Client reassembles by stream ID.
Connection: [css-frame][img-frame][js-frame][css-frame][img-frame]...
Stream 1: css -----> css -----> css (done)
Stream 2: img -----> img -----> img -----> img (done)
Stream 3: js ------> js (done)
No more HOL blocking at the HTTP level. No need for 6 connections or domain sharding.
But: still runs on TCP. If a single TCP packet is lost, all streams are blocked waiting for retransmit. HOL blocking moved down one layer.
HTTP/3 — QUIC over UDP
Drops TCP entirely. Uses QUIC — a protocol built on UDP that adds reliability per stream.
- HTTP/2 (TCP): one lost packet → all streams blocked
- HTTP/3 (QUIC): one lost packet → only that stream blocked, others keep flowing
Bonus: QUIC combines TCP + TLS handshake into a single handshake — faster first request.
Comparison
| HTTP Version | Transport | HOL Blocking? |
|---|---|---|
| HTTP/1.1 | TCP | Yes — HTTP level (one request at a time) |
| HTTP/2 | TCP | Solved at HTTP level, still exists at TCP level |
| HTTP/3 | QUIC (over UDP) | No — independent streams at transport level |
Communication Patterns
From simplest to most capable:
One-shot → HTTP request/response
Client keeps asking → Short polling
Server holds open → Long polling
Server streams → SSE (one-way)
Full duplex → WebSockets (two-way)
HTTP Request/Response
Client asks, server answers, done. Simple and stateless.
Short Polling
Client asks "anything new?" repeatedly on a timer. Server responds immediately (yes or no). Simple but wasteful — most responses are empty.
Long Polling
Client sends request. Server holds the connection open until it has data, then responds. Client immediately reconnects.
Tradeoff vs SSE: every response = tear down + reconnect. For frequent updates (e.g., stock ticker updating every second), this means a new HTTP request per update. Works everywhere though (just regular HTTP).
Server-Sent Events (SSE)
Client sends one HTTP request. Server responds with Content-Type: text/event-stream and never closes the response. Keeps streaming data as it becomes available.
- One direction only — server → client
- Connection stays open — no reconnection overhead
- ChatGPT uses SSE for token-by-token streaming
SSE > Long Polling when updates are frequent (avoids reconnection overhead). Long Polling > SSE when updates are rare or SSE isn't supported (older browsers, corporate proxies).
WebSockets
sequenceDiagram
participant Client
participant Server
Client->>Server: GET /chat HTTP/1.1<br/>Upgrade: websocket
Server-->>Client: HTTP/1.1 101 Switching Protocols<br/>Upgrade: websocket
Note over Client,Server: TCP connection is now a WebSocket
Client->>Server: message frame
Server->>Client: message frame
Server->>Client: message frame
Client->>Server: message frame
Note over Client,Server: Either side can send at any time
Starts as HTTP (passes through firewalls/proxies that understand HTTP), then upgrades — after the 101 response, the connection is no longer HTTP. It's a raw bidirectional TCP pipe where either side can send frames at any time.
Why SSE can't replace WebSockets: SSE is still an HTTP response stream. HTTP is fundamentally request → response. The client's side is "done" after the initial request — no mechanism to send data back on that stream. WebSockets ditch HTTP entirely after the upgrade.
Choosing the Right Protocol
| Use Case | Protocol | Why |
|---|---|---|
| Live sports scores | SSE | Server pushes updates, client just receives |
| Stock price ticker | SSE | Same — one-way stream of updates |
| ChatGPT streaming | SSE | Server streams tokens, client just reads |
| Chat (Slack, WhatsApp) | WebSockets | Bidirectional — users send AND receive |
| Uber rider app | WebSockets | Need both location updates (receive) AND messaging (send + receive) |
Key insight: once you already need WebSockets for one feature (e.g., messaging), route everything through it rather than maintaining two connection types. Use a type field in payloads to differentiate:
{"type": "location_update", "data": {"lat": 37.7, "lng": -122.4}}
{"type": "message", "data": {"from": "driver", "text": "I'm outside"}}
The WebSocket server acts as a gateway — holds the client connection and fans out to/from separate backend services (location service, messaging service, etc.). Services stay decoupled; the WS gateway multiplexes everything down one pipe to the client.
graph LR
R[Rider Client] <-->|Single WS Connection| GW[WS Gateway]
GW <--> LS[Location Service]
GW <--> MS[Messaging Service]