WebSocket là gì?

Trong thế giới web hiện đại, người dùng luôn đòi hỏi sự tức thời. Từ các ứng dụng nhắn tin trực tuyến (chat apps), bảng điều khiển dữ liệu tài chính (financial dashboards), cho đến các trò chơi trực tuyến nhiều người chơi, dữ liệu cần được cập nhật liên tục theo thời gian thực (real-time).
Trước đây, để làm được điều này, các lập trình viên thường phải sử dụng các kỹ thuật như HTTP Polling hoặc Long Polling – tức là trình duyệt phải liên tục gửi yêu cầu lên máy chủ để hỏi xem có dữ liệu mới hay không. Cách tiếp cận này giống như việc bạn liên tục mở cửa mỗi 5 giây để xem shipper đã giao hàng tới chưa, gây lãng phí tài nguyên, tốn kém băng thông và tạo ra độ trễ lớn.
Đó là lý do WebSocket ra đời. WebSocket mang đến một cuộc cách mạng bằng cách thiết lập một kênh giao tiếp hai chiều (bi-directional), toàn song công (full-duplex) và duy trì liên tục trên một kết nối TCP duy nhất. Giữa client và server giờ đây như có một đường dây điện thoại kết nối thẳng, cả hai bên có thể nói chuyện với nhau bất cứ lúc nào với chi phí thấp hơn.
Cơ chế hoạt động của WebSocket (Handshake)
Quy trình giao tiếp của WebSocket diễn ra qua ba giai đoạn chính nhằm tối ưu hóa tốc độ và băng thông truyền tải:
- Bắt tay (Handshake): Client gửi một HTTP GET Request đặc biệt (Upgrade Request) yêu cầu nâng cấp giao thức qua cổng TCP 80 (không bảo mật) hoặc cổng 443 (bảo mật). Nếu hỗ trợ, Server phản hồi mã
101 Switching Protocols. - Kết nối bền vững (Connection): Kết nối HTTP ban đầu được chuyển giao thành một kết nối TCP liên tục và được giữ mở cho đến khi một bên chủ động ngắt kết nối.
- Trao đổi dữ liệu (Data Transfer): Hai bên tự do gửi/nhận dữ liệu độc lập cùng lúc. Dữ liệu truyền tải dưới dạng các “khung” (frame) cực nhẹ, loại bỏ các HTTP Header cồng kềnh giúp tiết kiệm tối đa băng thông.

So sánh toàn diện: WebSocket vs HTTP
Để hiểu rõ tại sao WebSocket lại tối ưu cho các tác vụ real-time, hãy cùng đặt nó lên bàn cân với giao thức HTTP truyền thống:
| Tiêu chí | HTTP (Request/Response) | WebSocket (Full-Duplex) |
| Chiều giao tiếp | Một chiều (One-way): Client gửi yêu cầu, Server mới phản hồi. Server hoàn toàn không thể chủ động gửi dữ liệu trước. | Hai chiều (Bi-directional): Cả Client và Server đều có thể chủ động gửi tin nhắn cho nhau bất cứ lúc nào. |
| Trạng thái kết nối | Không trạng thái (Stateless): Phải liên tục mở và đóng kết nối cho mỗi request (hoặc dùng polling), gây tốn tài nguyên. | Hướng kết nối (Stateful): Kết nối được giữ mở liên tục (Persistent), giúp giảm tối đa độ trễ và tiết kiệm tài nguyên. |
| Dung lượng Header | Rất lớn: Mỗi request đều phải gửi kèm bộ HTTP Header cồng kềnh (Cookie, User-Agent, Token…), dẫn đến chi phí mạng cao. | Siêu nhẹ: Sau khi bắt tay thành công, các frame dữ liệu tiếp theo chỉ mang theo payload nhẹ, không chứa header rườm rà (chỉ tốn vài byte). |
| Độ trễ (Latency) | Cao vì trình duyệt phải thực hiện lại quá trình bắt tay TCP cho từng yêu cầu riêng lẻ. | Rất thấp do dữ liệu được đẩy đi ngay lập tức thông qua đường truyền có sẵn. |
| Mô hình phù hợp | Tải dữ liệu tĩnh, tài liệu, kiến trúc RESTful API thông thường. | Ứng dụng thời gian thực (Real-time), cập nhật và đồng bộ dữ liệu liên tục. |
Minh họa cơ bản
Để dễ hình dung cách hoạt động thực tế, chúng ta sẽ xây dựng một ví dụ đơn giản gồm hai phần: Client (chạy trên trình duyệt của người dùng) và Server (chạy trên máy chủ Node.js).
Lưu ý:
- Phía Server (Node.js): Bắt buộc cài thư viện ngoài (như
ws) vì Node.js mặc định chỉ hỗ trợ giao thức mạng cốt lõi cấp thấp. - Phía Client (Trình duyệt): Không cần cài gì cả vì trình duyệt hỗ trợ sẵn WebSocket API tiêu chuẩn. Bạn chỉ cần viết code và chạy trực tiếp.
Bước 1: Chuẩn bị thư mục dự án
- Tạo một thư mục mới trên máy tính (ví dụ tên là
websocket-demo). - Tạo 2 file bên trong thư mục này và dán đoạn code tương ứng trong bài viết của bạn vào:
server.js(Chứa đoạn code backend Node.js dùng thư việnws).client.js(Chứa đoạn code frontend dùng WebSocket API).
Bước 2: Cài đặt thư viện ws cho Server
- Mở ứng dụng Terminal (trên Mac/Linux) hoặc Command Prompt/PowerShell (trên Windows).
- Di chuyển vào thư mục dự án của bạn bằng lệnh
cd(ví dụ:cd đường_dẫn_đến_thư_mục/websocket-demo). - Chạy lệnh sau để cài đặt thư viện hỗ trợ cho server:
npm install ws
Phía Server (Node.js sử dụng thư viện ws)
File server.js đóng vai trò là “trung tâm điều phối”. Khác với giao thức HTTP thông thường (vốn sẽ ngắt kết nối ngay sau khi phản hồi một Request), WebSocket Server sẽ liên tục chạy ngầm để giữ kết nối và lắng nghe các Client thông qua cổng tự do 8080 (nhằm tránh xung đột với các cổng hệ thống mặc định như 80 và 443 trên máy cá nhân).
Chúng ta sẽ quản lý các sự kiện chính phía máy chủ bao gồm:
connection: Kích hoạt mỗi khi có một Client thực hiện bắt tay (Handshake) thành công và gia nhập vào hệ thống.message: Tiếp nhận tin nhắn gửi lên từ Client để xử lý logic và phản hồi ngược lại bằng hàmws.send().close: Phát hiện thời điểm Client tắt trình duyệt hoặc mất mạng để giải phóng tài nguyên hệ thống, tránh rò rỉ bộ nhớ (memory leak).
const WebSocket = require("ws");
// Khởi tạo một WebSocket Server chạy ở cổng 8080
const wss = new WebSocket.Server({ port: 8080 });
wss.on("connection", (ws) => {
console.log("Có một Client mới vừa kết nối!");
// Lắng nghe tin nhắn từ Client gửi lên
ws.on("message", (message) => {
console.log(`Nhận được tin: ${message}`);
// Phản hồi dữ liệu ngược lại cho đúng Client đó
ws.send(`Server đã nhận được tin nhắn của bạn: "${message}"`);
});
// Xử lý khi Client ngắt kết nối
ws.on("close", () => {
console.log("Client đã ngắt kết nối.");
});
});
Phía Client (Chạy trên trình duyệt):
Mở file client.js và dán đoạn code dưới đây vào. File này sẽ đóng vai trò khởi tạo kết nối thông qua giao thức ws:// đến cổng 8080 của Server, đồng thời sử dụng các sự kiện (Event Listeners) tích hợp sẵn của trình duyệt để quản lý vòng đời kết nối:
onopen: Kích hoạt ngay khi kết nối bắt tay thành công, cho phép gửi thông điệp chào hỏi đầu tiên lên Server bằng hàm.send().onmessage: Bộ lắng nghe dữ liệu liên tục. Mỗi khi Server chủ động đẩy thông tin mới xuống, sự kiện này sẽ bắt được để cập nhật giao diện thời gian thực.onerror&onclose: Giúp phát hiện các sự cố đường truyền hoặc nhận biết thời điểm kết nối bị ngắt.
// Kết nối tới WebSocket Server chạy trên máy cục bộ bằng ws://
// thay bằng wss:// nếu chạy trên server
const socket = new WebSocket("ws://localhost:8080");
// Kích hoạt khi kết nối mở thành công
socket.onopen = (event) => {
console.log("Đã kết nối tới Server!");
// Chủ động gửi tin nhắn lên Server
socket.send("Xin chào Server, tôi là Client!");
};
// Lắng nghe và nhận tin nhắn từ Server gửi về
socket.onmessage = (event) => {
console.log("Nhận tin nhắn từ Server:", event.data);
};
// Xử lý khi có lỗi kết nối xảy ra
socket.onerror = (error) => {
console.error("Lỗi WebSocket:", error);
};
// Xử lý khi kết nối bị đóng
socket.onclose = (event) => {
console.log("Kết nối đã đóng.", event.reason);
};
Bước 3: Hướng dẫn chạy và kiểm tra kết quả
Để xem cách hai file này nói chuyện với nhau theo thời gian thực, bạn thực hiện theo các bước sau:
- Khởi chạy Server: Tại cửa sổ Terminal đang mở ở thư mục dự án, chạy lệnh:
node server.js. Màn hình Terminal sẽ đứng im để duy trì trạng thái lắng nghe kết nối. - Khởi chạy Client: Mở một trình duyệt web bất kỳ (Chrome, Edge, Firefox…), nhấn phím F12 và chuyển sang tab Console.
- Kiểm tra luồng chạy: Hãy copy toàn bộ đoạn code trong file
client.js, dán trực tiếp vào cửa sổ Console của trình duyệt và nhấn Enter.
Kết quả thu được:
- Tại tab Console của trình duyệt, bạn sẽ thấy dòng chữ Đã kết nối tới Server! xuất hiện ngay lập tức, theo sau là phản hồi phản chiếu từ máy chủ: Nhận tin nhắn từ Server: Server đã nhận được tin nhắn của bạn: “Xin chào Server, tôi là Client!”.
- Tại cửa sổ Terminal đang chạy Server, bạn cũng sẽ nhận được các dòng nhật ký đồng bộ: Có một Client mới vừa kết nối! và Nhận được tin: Xin chào Server, tôi là Client!.

Bạn có thể xem source code tham khảo tại đây.
Ứng dụng thực tế của WebSocket
Nhờ khả năng truyền tải dữ liệu tức thì và liên tục theo thời gian thực, WebSocket là được sử dụng trong rất nhiều ứng dụng phổ biến hiện nay:
- Ứng dụng nhắn tin (Chat Apps): Facebook Messenger, Zalo, Slack… đều cần WebSocket để tin nhắn xuất hiện ngay lập tức trên màn hình người nhận mà không cần họ phải F5 lại trang.
- Bảng điều khiển tài chính & Crypto: Các sàn giao dịch chứng khoán, giá Bitcoin cần cập nhật biến động theo từng mili-giây. WebSocket giúp đẩy dữ liệu bảng giá liên tục từ server xuống màn hình người dùng.
- Trò chơi trực tuyến (Web Games): Các tựa game multiplayer chạy trên trình duyệt yêu cầu vị trí và hành động của các người chơi phải được đồng bộ liên tục với độ trễ thấp nhất có thể.
- Công cụ cộng tác thời gian thực: Google Docs, Figma, Trello… cho phép nhiều người cùng chỉnh sửa một tài liệu hoặc giao diện và nhìn thấy con trỏ chuột của nhau di chuyển theo thời gian thực.
- Hệ thống thông báo đẩy (Push Notifications): Các ứng dụng giao đồ ăn (Grab, ShopeeFood) sử dụng WebSocket để cập nhật vị trí tài xế theo thời gian thực trên bản đồ cho khách hàng.
Lưu ý khi nào KHÔNG nên dùng: Các trang web truyền thống chỉ cần tải dữ liệu một lần như trang đọc tin tức, blog cá nhân, hoặc trang giới thiệu doanh nghiệp thì không cần WebSocket. Khi đó, HTTP/2 hoặc HTTP/3 tiêu chuẩn sẽ tối ưu và tiết kiệm tài nguyên hệ thống hơn.
Các thư viện WebSocket phổ biến
Mặc dù việc sử dụng WebSocket thuần khá đơn giản, nhưng trong các dự án thực tế, bạn sẽ phải đối mặt với các bài toán như tự động kết nối lại khi mất mạng (reconnection), chia phòng chat (room/channel), hoặc hỗ trợ các trình duyệt cũ. Để giải quyết các vấn đề này, tùy thuộc vào ngôn ngữ và nền tảng của dự án, bạn có thể lựa chọn các thư viện phổ biến dưới đây:
Hoạt động ở cả Client & Server
- Socket.IO (JavaScript/Node.js): Thư viện real-time phổ biến nhất hiện nay. Nó tự động chuyển đổi qua lại giữa Long-Polling và WebSocket tùy theo độ hỗ trợ của môi trường, hỗ trợ tự động kết nối lại và chia phòng cực kỳ mạnh mẽ.
Chỉ hoạt động ở phía Server (Server-side)
ws(Node.js): Thư viện WebSocket thuần cho Node.js. Siêu nhanh, siêu nhẹ. Phía client chỉ cần dùng WebSocket API mặc định của trình duyệt để kết nối tới mà không cần cài thêm gì.- SignalR (.NET): Giải pháp mạnh mẽ nhất trong hệ sinh thái Microsoft, tự động quản lý kết nối và tối ưu hóa đường truyền.
- Channels (Python/Django): Giúp chuyển đổi dự án Django sang giao thức bất đồng bộ (ASGI) để xử lý mượt mà kết nối WebSocket.
Có thể bạn chưa biết?
- Hiểu về Đơn công, Bán song công và Toàn song công:
- Đơn công (Simplex): Giống như truyền hình Tivi hay Radio, tín hiệu chỉ đi một chiều duy nhất từ đài phát đến máy của bạn, bạn hoàn toàn không thể gửi dữ liệu ngược lại.
- Bán song công (Half-Duplex): Giống như dùng bộ đàm, tại một thời điểm chỉ một người được nói và người kia phải đợi đối phương nói xong mới có thể phản hồi. Giao thức HTTP truyền thống hoạt động theo cơ chế này (Client gửi request xong và đợi, Server mới trả lời).
- Toàn song công (Full-Duplex): Giống như một cuộc điện thoại, cả hai bên có thể nói và nghe cùng một lúc. Đây chính là cách WebSocket hoạt động, cho phép dữ liệu truyền đi hai chiều đồng thời không có độ trễ.
- Tại sao có tiền tố
ws://vàwss://? Tương tự như HTTP và HTTPS,ws://là giao thức WebSocket thuần (không bảo mật), cònwss://là WebSocket Secure (sử dụng mã hóa TLS/SSL). Trên môi trường Production thực tế, bạn luôn luôn nên dùngwss://để bảo vệ dữ liệu khỏi các cuộc tấn công nghe lén. Trong các bài hướng dẫn (như ví dụ trên), chúng ta dùngws://trênlocalhostđể lược bỏ bước cấu hình chứng chỉ SSL phức tạp giúp người học dễ thử nghiệm hơn. - Cơ chế “Giữ mạng sống” (Heartbeat): WebSocket giữ kết nối mở liên tục, nhưng nếu đường truyền “im lặng” quá lâu, các thiết bị mạng trung gian (như Router hoặc Tường lửa) có thể tự động ngắt kết nối. Để khắc phục, các hệ thống thường định kỳ gửi các gói tin trống siêu nhỏ gọi là Ping/Pong sau mỗi vài chục giây để báo hiệu cho nhau rằng: “Tôi vẫn đang online, đừng ngắt kết nối nhé!”.
- Giới hạn kết nối của trình duyệt: Hầu hết các trình duyệt hiện đại giới hạn tối đa khoảng 30 hành vi kết nối WebSocket đồng thời trên mỗi tên miền (domain). Tuy nhiên, trong thực tế một tab trình duyệt thường chỉ cần duy trì duy nhất một kết nối WebSocket là đã đủ để xử lý mọi luồng dữ liệu thời gian thực.
Lời kết
WebSocket đã thay đổi hoàn toàn cách chúng ta xây dựng và trải nghiệm các ứng dụng web. Bằng cách xóa bỏ ranh giới về độ trễ của giao thức HTTP truyền thống, nó mang lại trải nghiệm mượt mà và tức thời hơn cho người dùng. Mặc dù việc triển khai WebSocket đòi hỏi server phải quản lý và duy trì trạng thái kết nối phức tạp hơn, nhưng những giá trị mà nó mang lại cho các ứng dụng thời gian thực là hoàn toàn xứng đáng.
Hy vọng bài viết này đã giúp bạn có cái nhìn tổng quan và bắt đầu những bước đầu tiên với WebSocket. Hãy thử tự tay tạo một ứng dụng chat nhỏ để thấy sự kỳ diệu của công nghệ này nhé!


