WebSockets 101: How to Build Real-Time Apps
Today, we’re going to look at WebSockets. This is the tech that makes multiplayer games, chat apps, and live stock tickers actually work. We’ll also look at Socket.io, which is basically the cheat code for making WebSockets easy to use. We’ll keep the jargon to a minimum.
The Problem: The "Mailman" Model (HTTP)
To get why WebSockets are cool, you have to understand why standard websites are kind of annoying for real-time stuff. Think of standard HTTP like sending a letter via mail -
You - Send a letter asking "Do I have new messages?" (Request)
Server - Reads letter, checks database, writes back "No." (Response)
End of conversation.
If you want to check again 5 seconds later, you have to send a whole new letter. Basically http is stateless.
we used to solve this by making the browser ask the server every single second: "Any updates? Any updates? Any updates?" This is called Polling. It works, but it’s exhausting for your server and eats up your user’s data.
The Solution: The "Phone Call" (WebSockets)
WebSockets change the rules. Instead of mailing letters back and forth, you open a phone line.
You - Dial the server.
Server - Picks up.
The line stays open.
Now, nobody has to ask for updates. If the server has a message for you, it just speaks. If you have a message, you just speak. It’s a two way, persistent connection.
Let’s Build Something
Enough talk. Let's write some code. We’ll use Node.js for this.
If you want to follow along, create a folder, open your terminal, and run -
npm init -y. npm install express socket.io
1. The Backend (index.js)
Standard Express apps look one way, but when you add Socket.IO, you have to do a little "wrapping" of the server.
const express = require('express');
const http = require('http');
const { Server } = require("socket.io");
const app = express();
const server = http.createServer(app);
const io = new Server(server);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('A user connected! Socket ID:', socket.id);
socket.on('chat message', (msg) => {
io.emit('chat message', msg);
});
});
server.listen(3000, () => {
console.log('Server running on port 3000');
});
The important bits:
io.on('connection'): This runs every single time a new tab opens your site.socket.id: Every user gets a random, unique ID. This is how you tell users apart.io.emit: This shouts the message to everyone. If you usedsocket.emit, you'd only be whispering back to the person who sent the message.
2. The Frontend (index.html)
This is the HTML file the server will send to the browser.
<!DOCTYPE html>
<html>
<body>
<h1>Simple Chat</h1>
<input id="input" autocomplete="off" /><button onclick="sendMsg()">Send</button>
<ul id="messages"></ul>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
function sendMsg() {
const input = document.getElementById('input');
if (input.value) {
socket.emit('chat message', input.value);
input.value = '';
}
}
socket.on('chat message', function(msg) {
const item = document.createElement('li');
item.textContent = msg;
document.getElementById('messages').appendChild(item);
});
</script>
</body>
</html>
Is this the only way?
Short answer, NO. You don't always need WebSockets. WebSockets are heavy. They keep a connection open 24/7. Sometimes, that's overkill.
If you want to make your app feel realtime, we have 4 popular ways
Short polling
Long polling
SSE (server side events)
Web sockets
WebSockets feel like magic, but they are just a persistent phone call between your browser and the server. Socket.io just makes sure the call doesn't drop.