Refreshing for a Score That Changed Two Minutes Ago
Picture the last over of an IPL chase. You open the score app, see "IND 151/4, needs 8 off 6", and lock your phone. Fifteen seconds later you unlock it and check again — same number. You check again. And again. Somewhere around the eighth refresh, the score finally jumps to "IND 155/4, needs 4 off 4" and your heart rate goes up. What actually happened in those eight checks? Your phone sent eight separate messages to a server saying "anything new?", and seven of those eight times the server said "nope, same as before." Only the eighth check happened to land after something had actually changed. You did seven refreshes for nothing.
This behaviour — asking the same question over and over until the answer changes — is called polling, and it is how a huge number of web pages used to fake "live" updates before a better tool existed. The tool this chapter is about, the WebSocket, was designed specifically to remove this waste: instead of you repeatedly asking the server "anything new yet?", the server simply tells you the moment something changes, without being asked. To understand why that is such a different — and better — idea, we first need to be precise about how the web normally works, because WebSockets only make sense once you see the limitation they are fixing.
How the Web Normally Talks: One Question, One Answer, Done
Every time your browser loads a normal web page, image, or piece of data, it uses HTTP (HyperText Transfer Protocol). HTTP has a very rigid conversation pattern, and it is worth stating it precisely because the rest of this chapter depends on it:
- The client (your browser, or an app) opens a connection and sends a request — for example, "GET me the current score."
- The server processes that request and sends back exactly one response.
- The exchange is now finished. If the browser wants anything else — even one second later — it must start a brand-new request.
Notice the direction of control here: the client always speaks first. The server is not allowed to interrupt you with "hey, the score just changed!" — it can only ever reply to something you asked. This is called a request-response or client-initiated model, and it is perfectly fine for things that do not change often, like loading a Wikipedia article or an image. It becomes a real problem the moment the data changes faster than you can predict — a live score, a chat message from a friend, a stock price, or another player's move in a game. For those, the only way to stay "up to date" using plain HTTP is to keep re-asking, which is exactly the polling behaviour from the cricket example.
Doing the Arithmetic on Wasted Requests
Let's put real numbers on how wasteful polling gets, using approximate but realistic sizes so the arithmetic means something (these are illustrative figures for the calculation, not measurements of any specific company's app).
Suppose a live-score page polls the server every 2 seconds, and you keep the tab open for one full T20 over-heavy passage of play lasting 10 minutes.
- Number of poll requests in 10 minutes: 10 minutes = 600 seconds. At one request every 2 seconds, that's 600 ÷ 2 = 300 requests.
- Every single one of those requests carries overhead even when nothing has changed — a request line, headers like
Host,User-Agent,Accept, and cookies, plus the server's response headers. Let's estimate that overhead at roughly 600 bytes per request-response pair. Total overhead: 300 × 600 bytes = 180,000 bytes ≈ 176 KB. - Now, how many times did the score actually change in those 10 minutes? Cricket scores update roughly once a ball, so in a 10-minute stretch, maybe 20 meaningful updates happened.
- Out of 300 requests, only about 20 carried a genuinely new answer. The other 280 (about 93% of all requests) were pure waste — network traffic, battery drain, and server processing spent to learn "nothing changed."
Now compare that to a WebSocket approach for the same 10 minutes. There is one setup step (called a handshake, explained in the next section) costing roughly 300 bytes, and after that, the server sends a message only when the score actually changes — 20 times, each a short text like "IND 151/4 (19.0 ov)" plus a very small WebSocket frame overhead of only a few bytes. Call each message about 24 bytes. Total: 300 + (20 × 24) = 300 + 480 = 780 bytes.
Compare the two totals: 180,000 bytes versus 780 bytes. Dividing, 180,000 ÷ 780 ≈ 231. The polling version moved roughly 230 times more data to deliver the exact same 20 pieces of real information. That gap is the whole reason WebSockets exist: not because polling is impossible, but because it is enormously wasteful when updates are frequent and unpredictable.
One Phone Call Instead of Three Hundred Postcards
Here is the analogy that makes the difference stick. Plain HTTP polling is like mailing a postcard that says "anything new?", waiting for a reply postcard, then immediately mailing another identical postcard, over and over — even when you already know the answer is usually "no." A WebSocket is like making a phone call and simply staying on the line. Once the call connects, either person can speak at any moment without redialling. Your friend does not need you to ask "did anything happen?" before telling you the score — they just say it the instant it happens, because the line is already open.
This property — both sides able to send whenever they want, without waiting for permission — is called full-duplex communication. HTTP polling is closer to half-duplex, like a walkie-talkie where only one person can transmit at a time and the other must wait their turn to press the button. A regular phone call, and a WebSocket connection, are full-duplex: client and server can talk simultaneously and independently, and critically, the server is finally allowed to speak first — something plain HTTP never permits.
Formally: a WebSocket is a persistent, full-duplex communication channel between a client and a server, established once and kept open, over which either side can send messages at any time without a new request being made. It runs on top of TCP, the same reliable, ordered-delivery transport that HTTP itself uses — a WebSocket is not a separate physical wire, it is a different way of using the connection once it exists.
The Handshake: How a Normal HTTP Request Becomes a WebSocket
A subtlety students often miss: a WebSocket connection does not start as something exotic — it starts as an ordinary HTTP request, and then upgrades itself. This is deliberate, so that WebSocket traffic can travel through the same ports (80 and 443) and the same firewalls that already handle normal web traffic.
The sequence is:
- The browser sends a normal-looking HTTP GET request, but with two special headers:
Upgrade: websocketandConnection: Upgrade, plus a randomly generated key in a header calledSec-WebSocket-Key. - If the server understands and agrees, instead of the usual
200 OK, it replies with an unusual status code: 101 Switching Protocols. Its response includesUpgrade: websocketand a computed value inSec-WebSocket-Accept, proving it really is a WebSocket-aware server and not just something that echoed the request by accident. - At this exact moment, the underlying TCP connection stops behaving like HTTP. It does not close. Both sides now treat it as an open, bidirectional pipe, and either side may send a message at any time, with no further "requests" involved.
You address a WebSocket using a URL scheme just like HTTP's, except ws:// (unencrypted, analogous to http://) or wss:// (encrypted with TLS, analogous to https://). In real applications you should always use wss://, for the same reason you use https:// — without it, anyone on the same network could read or tamper with every message.
Writing the Browser Side: the WebSocket API
Every modern browser gives JavaScript a built-in WebSocket object. You do not need any library to use it — it is a global constructor, just like Date or Array. Here is a minimal client that connects to a live-score server and reacts to whatever it sends:
const socket = new WebSocket("wss://scores.example.in/live");
socket.onopen = function () {
console.log("Connected to score server");
socket.send("subscribe:IND-vs-AUS");
};
socket.onmessage = function (event) {
console.log("Score update:", event.data);
document.getElementById("score").textContent = event.data;
};
socket.onerror = function (error) {
console.log("Something went wrong:", error);
};
socket.onclose = function (event) {
console.log("Connection closed, code:", event.code);
};
Trace through what actually happens, in order, because the order matters for understanding full duplex:
new WebSocket(...)immediately starts the HTTP-upgrade handshake described above. It does not block — the rest of your script keeps running while the connection is being set up in the background.- The moment the server replies with
101 Switching Protocols, the browser firesonopen. Only now does"Connected to score server"get logged, and only now doessocket.send(...)actually transmit anything — callsendtoo early and there is no open connection to send on yet. - From this point on,
onmessagecan fire at any time, in any order relative to your own code, whenever the server decides to push something. If the server sends three updates at t=34s, t=41s, and t=96s,onmessagefires three separate times, once per message, each time with that message's text inevent.data— your script never asked for any of them. - If the connection drops (server restarts, phone loses signal, or you call
socket.close()yourself),onclosefires exactly once, carrying a numericevent.codethat tells you why it closed.
Compare this to how you would have to write the same feature using only plain HTTP requests: you would need a setInterval that fires every couple of seconds, calls fetch, waits for a response, and compares it to the last value it saw to decide whether anything changed. That is strictly more code, strictly more network traffic, and — worse — it can never be faster than your polling interval. A WebSocket update appears the instant the server sends it, whether that is 200 milliseconds after the last one or 20 minutes.
The Other End: What the Server Does
A WebSocket needs cooperation from server code too — you cannot get push updates from a server that was only ever built to answer HTTP requests one at a time. Here is a minimal Python server using the popular websockets library that plays the "Score Server" role from the diagram:
import asyncio
import websockets
scores = [
"IND 145/3 (18.2 ov)",
"IND 151/3 (19.0 ov) - SIX!",
"IND 151/4 (20.0 ov) - WICKET!",
]
async def send_score_updates(websocket):
for score in scores:
await websocket.send(score)
await asyncio.sleep(30)
async def main():
async with websockets.serve(send_score_updates, "localhost", 8765):
await asyncio.Future()
asyncio.run(main())
Trace it: websockets.serve starts listening on port 8765, and every time a browser completes the handshake against it, the library calls send_score_updates with a fresh websocket object representing that one connection. The function then loops through the three scores, calling await websocket.send(score) for each one, waiting 30 seconds between sends. Nothing in this function ever checks "did the client ask for anything?" — it just pushes, on its own schedule, exactly the behaviour that plain HTTP cannot offer. If two different phones connect at the same time, the library runs send_score_updates separately for each of them, so both get their own independent stream of the same three messages.
Misconception: "Isn't a WebSocket Just Polling Really Fast?"
This is the single most common confusion, and it is worth correcting precisely. Fast polling is still many separate HTTP connections — each one has its own handshake, its own headers, and its own "hello, goodbye." A WebSocket is one connection, opened once, that then stays alive for the entire session. The difference is not just speed, it is who is allowed to speak first. In polling, no matter how frequent, the client must always ask before the server can answer — the server can never volunteer information. In a WebSocket, after the one-time handshake, the server can send a message the very instant something happens, with zero request from the client triggering it. Making polling faster (say, once per 200 milliseconds) only shrinks the delay before you happen to ask at the right moment — it never removes the fundamental rule that the server cannot speak until spoken to. A WebSocket removes that rule entirely.
Misconception: "Real-time Is Always Better, So Use WebSockets Everywhere"
The opposite mistake is assuming WebSockets should replace HTTP requests generally. They should not. A WebSocket connection costs the server ongoing memory and an open TCP connection for as long as it stays connected — multiply that by millions of simultaneous users and it becomes expensive to keep alive, even when nobody is sending anything. For content that changes rarely — a news article, your school's syllabus page, a product listing — a plain HTTP request that fetches the page once is simpler, cheaper, and easier to cache than keeping a live connection open "just in case." The right question to ask before reaching for a WebSocket is: does this data change unpredictably, and does the user need to know the instant it changes? If yes — a live score, a chat message, another player's move, a stock tick — a WebSocket earns its cost. If the honest answer is "it changes once a day," plain HTTP wins.
Where This Already Runs Around You
Once you know what to look for, real-time push connections show up constantly in apps used across India. Stock and mutual-fund trading platforms need to show live price ticks without the user tapping refresh between every trade — a live price feed is exactly the "server pushes, client only listens" pattern this chapter describes, and several Indian brokerage trading APIs explicitly document a WebSocket endpoint for streaming market data for this reason. Ride-hailing apps that show a car icon crawling along a map in real time need the driver's location pushed to your screen every second or two without your phone re-requesting it constantly — a persistent connection is far cheaper on both battery and mobile data than the polling arithmetic we worked out earlier. Multiplayer mobile games, where your opponent's move must appear on your screen within a fraction of a second, and chat applications, where a message from a friend should appear the instant it is sent rather than when you next refresh, both rely on the same full-duplex idea. In every one of these cases, the underlying reason is identical to the cricket-score example: the data changes unpredictably, the user is watching, and asking "anything new?" on a timer would be both slower and far more wasteful than letting the server speak up the moment it has something to say.
Check Your Understanding
- Q: In plain HTTP, which side is allowed to start a new exchange of messages — the client, the server, or either?
A: Only the client. The server may only reply to a request; it can never send a message on its own initiative under plain HTTP. - Q: A WebSocket connection begins with a request that has status code 101 in the response. What is unusual about that, compared to a normal page load which returns 200?
A: 200 OK means "here is the resource you asked for, and this exchange is now finished." 101 Switching Protocols means "I agree to stop speaking HTTP and keep this same connection open for something else" — the connection continues instead of closing. - Q: If a live-score page polls every 3 seconds for 10 minutes (600 seconds), how many requests does it send, and if the score only changes 10 times in that period, what fraction of requests were wasted?
A: 600 ÷ 3 = 200 requests. Only 10 carried new information, so 190 out of 200 — 95% — were wasted asking "anything new?" and getting the same answer back. - Q: In the JavaScript example, if you call
socket.send(...)immediately afternew WebSocket(...), on the very next line, why might that fail?
A:new WebSocket(...)only starts the handshake; it does not wait for it to finish before returning. The connection is not actually open untilonopenfires, so sending before that point sends into a connection that is not ready yet. - Q: Give one example of data where plain HTTP is the better choice over a WebSocket, and explain why in one sentence.
A: Any example of rarely changing content — e.g., a school's exam timetable page — works, because keeping a connection open costs the server resources continuously, while the data itself might not change for days, so a single HTTP request when the page loads is cheaper and simpler.
Summary
Plain HTTP forces a rigid request-response pattern where the client must always ask first and the connection closes after each answer — fine for static content, wasteful for anything that changes unpredictably, since staying "live" then requires repeatedly polling and throwing away most of the answers. A WebSocket fixes this by starting as a normal HTTP request that includes an Upgrade: websocket header, and upon receiving a 101 Switching Protocols response, keeps that same TCP connection open for the rest of the session as a full-duplex channel — both client and server can send messages at any moment, with the server finally able to push data without being asked. In code, this shows up as the browser's WebSocket object with its onopen, onmessage, onerror, and onclose events, paired with server code (such as Python's websockets library) that can call send on its own schedule rather than only in reply to a request. The two things worth remembering precisely: a WebSocket is not "polling but faster" — it is a single persistent connection where the server can speak first — and it is not automatically better for everything, since holding a connection open has a real cost that only pays off when data genuinely changes fast and unpredictably, as with live scores, chat, trading prices, ride tracking, and multiplayer games.
Think About It
Think about this: How would you explain websockets: real-time communication to a friend who has never seen a computer? What real-world analogy would you use? Imagine you had to build a system using these concepts — what would be your first step? Try this: before moving on, write down three things you learned and one question you still have.
Practice Exercises
Now it is time to practice! Complete these challenges to solidify your understanding:
- Exercise 1: Write a short program that demonstrates the core concept from this chapter. Test it with at least 3 different inputs.
- Exercise 2: Find a real-world example where websockets: real-time communication is used in an Indian company (like TCS, Infosys, Flipkart, or ISRO). Write a paragraph explaining the connection.
- Exercise 3: Create a mind-map connecting websockets: real-time communication to at least 3 other topics you have studied.