Complete "Understanding the WebSocket Protocol and HTTP Differences" first to unlock this lesson.Go to previous lesson

Introduction

WebSocket is a protocol that enables full-duplex, persistent connections between client and server over a single TCP socket. Unlike plain HTTP where the client must request and the server responds, a WebSocket connection stays open and both sides can send messages at any time. This makes it perfect for chat apps, live dashboards, multiplayer games, and any feature that needs real-time updates.

In this lesson you will build the smallest possible WebSocket setup: a server in Node.js using the popular `ws` library, and a browser client that connects to it and exchanges a few messages. No frameworks, no databases — just the raw protocol so you understand what is happening under the hood.

Setting Up the Project

Create a new folder for the project and initialize it. You need Node.js installed (version 18 or later is fine).

bash
mkdir ws-demo
cd ws-demo
npm init -y
npm install ws

The `ws` package is a fast, widely-used WebSocket implementation for Node.js. After `npm install`, you will have a `node_modules` folder and a `package.json` that lists `ws` as a dependency.

Writing the Server

Create a file called `server.js`. The server does three things: import the library, create a WebSocket server bound to a port, and define what happens on connection and on incoming messages.

javascript
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
console.log('A client connected');
ws.on('message', (data) => {
const text = data.toString();
console.log('Received:', text);
ws.send(`Server echo: ${text}`);
});
ws.send('Welcome to the WebSocket server!');
});
console.log('WebSocket server is listening on ws://localhost:8080');

The `connection` event fires once per client that connects. The callback receives a `ws` object representing that individual client's socket. Inside the callback you attach a `message` listener. When a message arrives, `data` is a Buffer by default, so `toString()` converts it to plain text. The server then echoes the message back prefixed with `Server echo:`.

Run the server with `node server.js`. You should see the "listening" log line and nothing else until a client connects.

sơ đồ luồng kết nối — client gửi CONNECT, server chấp nhận, hai bên gửi MESSAGE qua lại trên cùng một socket duy nhất

Writing the Browser Client

Create a file called `index.html`. A browser can open a WebSocket connection using the built-in `WebSocket` global — no library needed on the client side.

markup
<!DOCTYPE html>
<html>
<head><title>WebSocket Demo</title></head>
<body>
<h1>WebSocket Demo</h1>
<input id="msg" placeholder="Type a message" />
<button id="send">Send</button>
<ul id="log"></ul>
<script>
const log = document.getElementById('log');
const ws = new WebSocket('ws://localhost:8080');
ws.addEventListener('open', () => {
log.innerHTML += '<li>Connected to server</li>';
});
ws.addEventListener('message', (event) => {
log.innerHTML += '<li>From server: ' + event.data + '</li>';
});
document.getElementById('send').addEventListener('click', () => {
const input = document.getElementById('msg');
ws.send(input.value);
input.value = '';
});
</script>
</body>
</html>

The `open` event fires when the handshake completes. After that, `ws.send('text')` sends a string message to the server. The server's echoed reply arrives as a `message` event whose `event.data` is the string the server sent.

Testing It End to End

Start the server with `node server.js`. Then open `index.html` in your browser (you can double-click it, or use a tool like `npx serve`). In the terminal you should see "A client connected" the moment the page loads. Type something in the input box and click Send. The browser log will show your message prefixed with `Server echo:`, and the terminal will log each message the server receives.

Common Mistakes

Forgetting `data.toString()` on the server side gives you a raw Buffer object instead of the readable string the client sent. Forgetting the `ws://` protocol prefix in the browser URL will throw a syntax error because the `WebSocket` constructor requires the full URL including scheme. If the server is not running, the browser's `open` event will never fire and you will see no log entries — always check the terminal first when nothing happens.

Summary

You now have a working WebSocket echo server and a browser client. The server uses `ws` to listen on port 8080, accepts connections, and echoes back any message it receives. The client opens the connection with `new WebSocket('ws://localhost:8080')` and uses `send` and `message` events to communicate. This pattern — one server, many connected clients, bidirectional messages — is the foundation every real-time feature builds on.

Lesson practice

Lesson Checkpoint

Review what you learned and get feedback on your work.

0/1
Answered · 0/1