WebSocket là một giao thức phổ biến trong các ứng dụng thời gian thực nhằm trao đổi thông tin một cách trực tuyến và liên tục giữa client và server hoặc giữa client và client. Bài viết hôm nay chúng ta cùng nhau tìm hiểu về WebSocket cũng như module Socket.io trong NodeJS để hiểu về cách thức hoạt động của nó nhé.
WebSocket là gì?
WebSocket là một giao thức truyền thông máy tính (computer communication protocol) cung cấp kênh liên lạc dạng full-duplex (song công hoàn toàn) qua một kết nối TCP. Không giống với giao thức HTTP là cần client chủ động gửi yêu cầu cho server rồi chờ đợi nhận dữ liệu; với WebSocket thì server có thể chủ động gửi thông tin đến client (và ngược lại) mà không cần phải có yêu cầu từ client.
Với tính chất trên, WebSocket thường được sử dụng để xây dựng các ứng dụng realtime thật sự như chat, chỉnh sửa tài liệu online (ví dụ như Google Docs), chơi game online, … Để sử dụng được WebSocket, chúng ta phải có server WebSocket; hiện nay thì hầu hết các ngôn ngữ lập trình Backend Web phổ biến đều hỗ trợ (có các thư viện) để phục vụ cho việc xây dựng WebSocket.
Các thao tác làm việc với WebSocket
Bước 1: Ở phía client, để bắt đầu kết nối với server WebSocket , bạn cần tạo ra 1 đối tượng WebSocket mới cung cấp URL endpoint đến server.
var ws = new WebSocket(url)
var ws = new WebSocket(url, protocols)
tùy chọn protocols chỉ định sub-protocol dành cho các server hỗ trợ.
Kết nối này sẽ nâng cấp từ giao thức HTTP lên giao thức WebSocket trong bước 2 (Handshake) qua cùng một kết nối TCP cơ bản
Bước 2: Handshake – client và serer bắt tay – đồng ý sử dụng giao thức WebSocket
Đầu tiên client gửi một http request yêu cầu việc bắt tay có dạng:
GET /mychat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13
Origin: http://example.com
Server sẽ trả về response:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
Client kiểm tra status trả về 101 hay không để xác nhận rằng việc kết nối (bắt tay) đã thành công.
Bước 3: Thực hiện việc truyền dữ liệu giữa 2 bên
Bản chất của WebSocket là khi kết nối được mở, ứng dụng sẽ có thể lắng nghe các sự kiện xảy ra (events) và có thể gửi các thông tin (data) đi. Để thực hiện việc truyền dữ liệu giữa 2 bên client – server, bạn sẽ sử dụng các phương thức và sự kiện sau:
- onopen: event khi handshake thành công và kết nối được thiết lập
- onmessage: event khi nhận được dữ liệu qua WebSocket
- onerror: event khi kết nối với WebSocket bị đóng bởi có lỗi nào đó xảy ra
- send(data): method gửi dữ liệu (data) qua WebSocket
- close(): method đóng kết nối đang tồn tại
Bước 4: Đóng kết nối khi một trong hai bên thực hiện việc ngắt kết nối đang tồn tại
// Close the WebSocket connection
ws.close(1000, "Closing Connection Normally");
Khi một trong 2 bên đóng kết nối thì sẽ không thực hiện được việc gửi dữ liệu nữa. Việc đóng kết nối cũng có thể xảy ra do một lỗi (error) nào đó phát sinh trong quá trình thực hiện.
Socket.io là gì?
Socket.io là một thư viện mã nguồn mở được phát triển từ năm 2010, hỗ trợ mạnh mẽ giao thức WebSocket giúp lập trình viên thuận tiện hơn trong việc xây dựng các ứng dụng realtime. Lưu ý là Socket.io không chỉ hỗ trợ giao thức WebSocket, nó còn có thể được thiết lập với HTTP long-polling hay Web Transport. Socket.io vẫn sử dụng giao thức WebSocket để kết nối, tuy nhiên có bổ sung thêm metadata vào mỗi gói tin được truyền đi. Điều này dẫn đến việc Socket.io client không thể kết nối đến WebSocket server và ngược lại, WebSocket client cũng không thể kết nối đến Socket.io server.
Một số tính năng quan trọng mà Socket.io cung cấp giúp nâng cao sự thuận tiện khi làm việc với WebSocket:
- Cơ chế dự phòng HTTP long-polling: với các browsers không hỗ trợ WebSocket, Socket.io cho phép sử dụng kỹ thuật HTTP long-polling để thực hiện việc kết nối và trao đổi dữ liệu
- Tính năng tự động kết nối lại: trong một số điều kiện cụ thể, kết nối giữa client và server có thể bị gián đoạn. Cơ chế heartbeat trong Socket.io giúp kiểm tra định kỳ trạng thái kết nối và sẽ cố gắng kết nối lại nếu cần
- Packet buffering: cơ chế lưu các tin nhắn vào bộ đệm để tránh trường hợp mất kết nối tạm thời
- Acknowledgements: tín hiệu xác nhận nhằm đảm bảo rằng tin nhắn đã được khách hàng nhận hoặc ngược lại
- Broadcasting: tính năng cho phép dễ dàng gửi tin nhắn đến nhiều client (khách hàng) cùng một lúc
- Multiplexing: tính năng ghép kênh, cho phép tạo nhiều không gian tên độc lập trên cùng một kết nối thông qua khái niệm namespace
Ví dụ sử dụng Socket.io
//client
<html>
<body>
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js" integrity="sha384-2huaZvOR9iDzHqslqwpR87isEmrfxqyWOF7hr7BY6KG0+hVKLoEXMPUJw3ynWuhO" crossorigin="anonymous"></script>
<script>
$(function () {
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
});
});
</script>
</body>
</html>
//server
var io = require('socket.io')(http);
io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
Với đặc trưng mạnh mẽ và dễ sử dụng, Socket.io đang ngày càng được sử dụng rộng rãi từ những trang mạng xã hội cần sự tương tác cao, đến các blog hay các trang web thương mại.