What Real-Time Communication Actually Means

WebSockets & Real-Time Communication — What Real-Time Communication Actually Means
WebSockets & Real-Time Communication
Chapter 1 · What Real-Time Communication Actually Means

⚡ What Real-Time Communication Actually Means

HTTP was built around a simple shape: the client asks, the server answers, the connection closes. That shape has no room for the server to say something first — a new chat message, a live score, a stock price tick — without the client asking again. Every "real-time" technique in this course is really a different workaround for that one limitation, each with its own cost.

Polling: Just Ask Again

The simplest workaround — repeatedly ask the server "anything new?" on a timer:

setInterval(async () => { const response = await fetch("/api/messages/latest"); const messages = await response.json(); renderMessages(messages); }, 3000); // ask every 3 seconds, whether or not anything changed

The Cost

Most requests come back with nothing new — wasted requests, wasted server load, and up to a full polling interval of latency before a real update is even noticed.

Where It's Still Fine

Genuinely low-urgency data — a dashboard that refreshes every 30 seconds is polling done reasonably, not a mistake.

Long Polling: Ask, Then Wait

A refinement — the client asks, but the server holds the request open until it actually has something to say (or a timeout passes), then the client immediately asks again:

async function longPoll() { const response = await fetch("/api/messages/wait-for-next"); // server holds this open const message = await response.json(); renderMessage(message); longPoll(); // immediately ask again }

Lower latency than plain polling, but it's still fundamentally request/response — every message round-trips through a brand new HTTP request, headers and all.

📡 Server-Sent Events: One-Way, Kept Simple

SSE opens one long-lived HTTP connection and lets the server push events down it whenever it wants — no new request needed per message, but strictly server-to-client only:

const events = new EventSource("/api/messages/stream"); events.onmessage = (event) => { const message = JSON.parse(event.data); renderMessage(message); }; // The browser automatically reconnects if the connection drops — // a real advantage SSE has over hand-rolled reconnection logic.

Genuinely Simpler Than WebSockets

Plain HTTP under the hood, automatic reconnection built into the browser, works through most proxies without special configuration.

The Limitation

One direction only — fine for a live score feed or a notification stream, useless the moment the client needs to send something back over the same channel.

WebSockets: Genuinely Two-Way

A WebSocket is a single connection that stays open and lets either side send a message at any time — the only one of these four techniques that's truly full-duplex:

const socket = new WebSocket("wss://example.com/chat"); socket.onmessage = (event) => renderMessage(JSON.parse(event.data)); sendButton.addEventListener("click", () => { socket.send(JSON.stringify({ text: input.value })); // client -> server, any time });

📊 Choosing the Right Tool

TechniqueDirectionLatencyComplexity
PollingClient → Server (repeated)Up to one intervalTrivial
Long PollingClient → Server (held open)LowModerate
SSEServer → Client onlyInstantLow
WebSocketsBoth directionsInstantHighest

Matching the Tool to the Job

SSE Is Enough

Live sports scores, a stock ticker, a notification bell, a build-status dashboard — anything where only the server ever has news to share.

WebSockets Are Needed

Chat, multiplayer games, collaborative editing, anything where the client needs to send data back over the same live connection.

💻 Coding Challenges

Challenge 1: Identify the Right Technique

For each of the following, name the most appropriate technique from this chapter and justify it in one sentence: (a) a live cryptocurrency price ticker, (b) a two-player tic-tac-toe game, (c) a "new version available, refresh?" banner.

Goal: Practice matching a real-time requirement to the least complex tool that actually satisfies it.

→ Solution

Challenge 2: Implement Naive Polling, Then Improve It

Write a polling loop that checks /api/status every 5 seconds, then rewrite it as long polling against a (described, not implemented) /api/status/wait endpoint that holds the request open until the status actually changes.

Goal: Practice feeling the concrete difference in latency and request volume between the two approaches.

→ Solution

Challenge 3: Set Up an SSE Connection

Write client-side code using EventSource to connect to /api/notifications/stream, log every incoming event, and handle the connection's onerror event by logging a reconnection attempt message.

Goal: Practice the basic SSE client API before WebSockets are introduced in the next chapter.

→ Solution

⚠️ Gotcha: Reaching for WebSockets by Default

WebSockets are the most powerful tool in this chapter and also the most complex to run correctly in production — connection state to manage, reconnection logic to write by hand, load balancer configuration to get right (covered in Chapter 7). A live dashboard that only ever needs the server to push updates is a worse system with WebSockets than with SSE: same real-time feel, more moving parts, more that can go wrong. Reach for WebSockets specifically when the client genuinely needs to talk back over the same connection — not by default because it sounds more "real-time."

🎯 What's Next

With the landscape mapped out, the next chapter goes under the hood of the technique this course is really about: The WebSocket Protocol — the HTTP Upgrade handshake, full-duplex framing, and what ws:// and wss:// actually mean on the wire.