Stage 1 · Code
Building Web Services
Realtime Communication Basics
Normal HTTP is a conversation with a clear goodbye. Realtime systems keep the line open, so the server can speak again later instead of waiting for the client to ask again.
Why Normal HTTP Cannot Push
A normal HTTP request is like placing a phone call where only one side is allowed to speak once. The client calls, asks for something, hears the answer, and the call ends. After that response is finished, the server has nowhere to send a surprise follow-up message. The socket is closed, the request is done, and the relationship is over.
That is why polling exists. If a browser wants fresh updates, it keeps asking again and again: 'anything new yet?' Polling works, but it is wasteful when nothing changes. Realtime systems try to avoid that repeated asking by keeping a longer-lived communication path open.
| Approach | Who speaks first each time? | Trade-off |
|---|---|---|
| Plain request/response | Client every time | Simple, but no server push after the response ends |
| Polling | Client every time | Easy to understand, but chatty and often wasteful |
| Server-Sent Events | Client opens once, server can keep streaming text events | Great for one-way server updates |
| WebSocket | Client starts with HTTP, then both sides can keep sending messages | More flexible, but connection state becomes your responsibility |
The core shift is not magical speed. It is connection lifetime. Instead of answering once and disappearing, the server keeps the line available for future messages.
Keeping the Connection Open
There are several ways to keep that path alive. A server can hold an HTTP response open and stream updates over time. It can let the client reconnect repeatedly with long polling. Or it can upgrade the connection into a more conversational protocol, such as WebSocket, where either side can send messages after the initial handshake.
For this lesson, keep the framing architectural. We are not trying to build a production chat system from scratch. We are building the mental model: a long-lived connection, a loop that writes updates, and a rule for when that loop stops.
The WebSocket Upgrade Idea
WebSocket begins as an HTTP request because browsers and servers already know how to make that first contact. The client sends a request that includes upgrade headers. If the server agrees, it answers with 101 Switching Protocols. That status code means: 'we started as HTTP, but from this point forward we are speaking a different, longer-lived protocol on the same connection.'
GET /live/clock HTTP/1.1
Host: example.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: abc123example
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocketThe exact cryptographic details of the handshake matter in a real implementation, but the big idea is simpler: an ordinary HTTP request asks permission to stop being ordinary HTTP.
The Go standard library gives you the HTTP request and response pieces, but not a high-level WebSocket API. In practice, teams often use a small helper package to perform the upgrade and frame parsing. The code below focuses on the message flow after that upgrade, not on production-ready framing details.
Notice the stop condition. Realtime code always needs one. If the browser tab closes, network dies, or the user navigates away, the server must stop its loop and release resources. That is why r.Context().Done() and write errors matter so much in long-lived handlers.
Tracing a Live Message Flow
client -> server: GET /live/clock with upgrade headers
server -> client: 101 Switching Protocols
server -> client: build queue heartbeat 10:00PM
server -> client: build queue heartbeat 10:02PM
server -> client: build queue heartbeat 10:04PM
client closes tab
server stops write loopThe repeated push is the whole point. Once the connection is upgraded and stays alive, the server can send the next update when it has one instead of waiting for the client to ask again.
Quiz and Practice
Why can a normal finished HTTP response not push a later surprise update to the client?
Hands-On Project
Write `FormatSSE(event, data string) string` so it returns one valid Server-Sent Events frame in the format `event: <event>` then a newline, `data: <data>` then a blank line. This is not WebSocket framing, but it reinforces the idea of keeping one HTTP response open and sending multiple structured updates over time.
Summary and Key Takeaways
- Plain request/response HTTP cannot send extra later messages after the response finishes.
- Realtime systems work by keeping a communication path open long enough for later updates.
- A WebSocket starts with HTTP, then upgrades the connection so both sides can keep sending messages.
- The crucial realtime loop is simple in concept: wait, send, repeat, stop cleanly on disconnect.
- Connection cleanup matters just as much as message delivery in long-lived systems.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.