Hiện nay, WebSocket được biết đến rộng rãi như 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 trực tuyến hai chiều và liên tục giữa client và server, client và client.
Với Socket.IO là công cụ nổi tiếng và hỗ trợ mạnh mẽ giao thức WebSocket với các tính năng nổi bật. Trong bài viết hôm nay chúng ta sẽ cùng tìm hiểu giao thức WebSocket cũng như những kiến thức cơ bản về thư viện Socket.IO.
1. Giao tiếp thời gian thực
1.1 Half duplex
Với giao thức truyền thống HTTP/1.0 và HTTP/1.1 trong mô hình client - server, client gửi một yêu cầu HTTP đến server, server xử lý và gửi kết quả trả về cho client, bao gồm trang HTML cũng như các thông tin liên quan. HTTP/1.0 đã đủ để thực hiện một yêu cầu lấy tài liệu từ một server.
Với HTTP/1.1 thêm vào các kết nối tái sử dụng, trình duyệt có thể khởi tạo một kết nối đến một server web để lấy các trang HTML, sau đó sử dụng cùng một kết nối để lấy nguồn tài nguyên như hình ảnh, chữ viết, và như vậy. HTTP / 1.1 giảm độ trễ giữa yêu cầu bằng cách giảm số lượng các kết nối đã được thực hiện từ các client đến các server.
Về bản chất, HTTP cũng là half-duplex, có nghĩa là lưu lượng truyền tin theo một hướng duy nhất tại một thời điểm, điều này gây lãng phí và kém hiệu quả.
Ahalf-duplex
1.2 Full duplex
Hiện nay ứng dụng web đã phát triển khác xa so với ngày đầu nó xuất hiện, kèm theo đó là vô số các kỹ thuật mới được áp dụng để phục vụ cho quá trình này nhằm đem lại trải nghiệm mới mẻ, đầy hứng thú và cũng không kém phần tiện dụng cho người dùng.
Công nghệ web thời gian thực (realtime) ngày càng trở nên phổ biết. Có nhiều công nghệ, phương pháp giúp xây dựng ứng dụng thời gian thực có thể kể đến như
- AJAX LONG-POLLING
- SERVER SENT EVENTS (SSE)
- COMET
- WEBSOCKET
Và các công nghệ yêu cầu "thời gian thực" hoặc gần như "thời gian thực" hiện nay thì half-duplex không còn thể đáp ứng. Cho đến hiện tại,
WEBSOCKET
dạng full-duplex đươc tích hợp trong HTML 5 đang trở lên chiếm ưu thế tuyệt đối.Afull-duplex
2. WebSocket
2.1 WebSocket là gì?
Giao thức
WebSocket
là một tiêu chuẩn mở được hỗ trợ rộng rãi để phát triển các ứng dụng thời gian thực. Các phương pháp trước đây để mô phỏng kết nối song công hoàn toàn dựa trên Polling, một phương pháp đồng bộ trong đó client đưa ra yêu cầu tới server để xem liệu có bất kỳ thông tin nào có sẵn hay không.Tính năng Polling hoạt động tốt trong trường hợp biết chính xác khoảng thời gian có sẵn của tin nhắn. Tuy nhiên, trong hầu hết các ứng dụng thời gian thực, tần suất tin nhắn thường không thể đoán trước được. Ngoài ra, polling yêu cầu client mở và đóng nhiều kết nối không cần thiết.
Long Polling (còn được gọi là Comet) là một phương thức liên lạc phổ biến khác trong đó client mở kết nối với server trong một khoảng thời gian nhất định. Nếu server không có bất kỳ thông tin nào, nó sẽ giữ yêu cầu mở cho đến khi có thông tin hoặc hết thời hạn được chỉ định (hết thời gian chờ).
Về cơ bản, Comet trì hoãn việc hoàn thành phản hồi HTTP cho đến khi server có thứ gì đó cần gửi cho client, một kỹ thuật thường được gọi là hanging-GET hoặc pending-POST.
Việc client phải liên tục kết nối lại với server để có thông tin mới khiến Long Polling trở thành một lựa chọn khá tệ đối với nhiều ứng dụng thời gian thực.
WebSocket
là một giao thức truyền thông máy tính (computer communication protocol), cung cấp các kênh liên lạc dạng full-duplex (song công) qua một kết nối TCP. Giao thức WebSocket
hiện nay được bao hàm ngay ở mục Connectivity trong đặc tả của HTML5.WebSocket
is a computer communications protocol, providing full-duplex communication channels over a single TCP connection.Nguồn: WebSocket - WikipediaSử dụng
WebSocket
, bạn có thể tạo ra những ứng dụng realtime thật sự như chat, chỉnh sửa tài liệu online (ví dụ Google docs), giao dịch hoặc game online nhiều người chơi...2.2 WebSocket API
2.2.1 Handshake
Khi tạo kết nối
WebSocket
, bước đầu tiên client và server cần làm là bắt tay (handshake) qua TCP, qua đó client và server đồng ý sử dụng giao thức WebSocket
.Handshake từ phía client có dạng như sau:
Handshake từ phía server có dạng như sau:
Để xác nhận việc kết nối, client sẽ gửi một giá trị
Sec-WebSocket-Key
được mã hóa bằng Based64
đến server.Sau đó bên server sẽ thực hiện:
- Nối thêm một chuỗi cố định quy định bởi giao thức
WebSocket
là258EAFA5-E914-47DA-95CA-C5AB0DC85B11
vào Sec-WebSocket-Key để được chuỗi mới làdGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
.
- Thực hiện mã hóa
SHA-1
chuỗi trên để được1d29ab734b0c9585240069a6e4e3e91b61da1969
.
- Mã hóa kết quả vừa nhận được bằng
Base64
để đượcs3pPLMBiTxaQ9kYGzzhZRbK+xOo=
.
- Gửi response lại client kèm với giá trị
Sec-WebSocket-Accept
chính là chuỗi kết quả vừa tạo ra.
Client sẽ kiểm tra status code (phải bằng 101) và
Sec-WebSocket-Accept
xem có đúng với kết quả mong đợi không và thực hiện kết nối.Sau khi handshake được thiết lập, API
WebSocket
cho phép ứng dụng của bạn kiểm soát giao thức WebSocket
và phản hồi các sự kiện do server kích hoạt. Vì API hoàn toàn được điều khiển theo sự kiện nên khi kết nối song công hoàn toàn được thiết lập.Khi server có dữ liệu cần gửi cho client hoặc nếu tài nguyên mà ứng dụng đang giám sát thay đổi trạng thái, nó sẽ tự động gửi dữ liệu hoặc thông báo. Với API hướng sự kiện, không cần phải thăm dò server để biết trạng thái cập nhật nhất của tài nguyên được nhắm mục tiêu.
2.2.2 Tạo một kết nối WebSocket
Để kết nối với server từ xa, hãy tạo một phiên bản đối tượng
WebSocket
mới và cung cấp cho đối tượng mới URL của điểm cuối đích (endpoint).Kết nối
WebSocket
được thiết lập bằng cách nâng cấp từ giao thức HTTP lên Giao thức WebSocket
trong quá trình bắt tay ban đầu giữa client và server, qua cùng một kết nối TCP cơ bản.Tiêu đề nâng cấp
Upgrade
được bao gồm trong yêu cầu này để thông báo cho server rằng client muốn thiết lập kết nối WebSocket
. Sau khi thiết lập kết nối thành công, các tin nhắn WebSocket
sẽ được gửi và nhận bằng phương pháp được định nghĩa bởi giao diện WebSocket
.Để tạo kết nối, hãy gọi hàm tạo
WebSocket
của Javascript, hàm này trả về đối tượng phiên bản kết nối. Sau đó bạn có thể lắng nghe các sự kiện trên đối tượng đó. Những sự kiện này được kích hoạt khi kết nối mở hoặc đóng, có tin nhắn đến hoặc xảy ra lỗi.Hàm tạo
WebSocket
lấy một đối số bắt buộc URL. Ngoài ra có thêm một số đối số tùy chọn chỉ định một giao thức:- url - bắt buộc: đường dẫn URL mà bạn muốn thiết lập kết nối
- protocols tuỳ chọn: một string hoặc mảng string protocol. Những string này để chỉ định sub-protocol, từ đó một server có thể áp dụng nhiều sub-protocol
WebSocket
(ví dụ một server có thể xử lý những loại tương tác khác nhau tuỳ thuộc vào protocol được chỉ định)
2.2.3 WebSocket Events
Bản chất không đồng bộ của
WebSocket
có nghĩa là miễn là kết nối WebSocket
được mở, ứng dụng có thể lắng nghe các sự kiện.Để bắt đầu lắng nghe các sự kiện, hãy thêm các hàm gọi lại vào đối tượng
WebSocket
hoặc sử dụng phương thức DOM addEventListener()
để thêm trình xử lý sự kiện vào đối tượng WebSocket.Một đối tượng
WebSocket
có thể gửi 4 sự kiện sau đây:- Open: Server phản hối yêu cầu kết nối
WebSocket
. Nó cho biết handshake đã được thực hiện và kết nối đã thiết lập. Callback cho sự kiện này làonopen
.
- Message: Xảy ra khi nhận data thông qua
WebSocket
. Callback để gọi sự kiện này làonmessage
.
- Error: Xảy ra khi kết nối với
WebSocket
đóng bởi vì một lỗi nào đó (ví dụ data không thể gửi). Callback tương ứng làonerror
.
Chú ý: khi xảy ra error cũng có thể đóng kết nối
WebSocket
.- Close: Xảy ra khi kết nối
WebSocket
đóng. Callback tương ứng làonclose
.
2.2.4 WebSocket Methods
WebSocket
cung cấp hai phương thức là:- send(): phương thức socket.send(data) vận chuyển data thông qua kết nối WebSocket. Nếu vì lý do nào đó mà kết nối không khả thi hoặc kết nối đóng, thì sẽ trả về exception về trạng thái kết nối không hợp lệ.
- close(): công cụ socket.close() được dùng để ngắt kết nối đang tồn tại. Hoặc khi kết nối đã đóng rồi thì sẽ không làm gì cả. Sử dụng với 2 tham số: code (mã trạng thái), reason (chuỗi văn bản giải thích).
2.2.5 Thuộc tính của đối tượng WebSocket
Một đối tượng kết nối
WebSocket
cũng có những thuộc tính sau:- url (read-only): Trả về URL được thiết lập khi khởi tạo.
- readyState (read-only): Thể hiện trạng thái của kết nối, có thể có các giá trị sau đây:
- 0: kết nối đang tiến triển và vẫn chưa được thiếp lập.
- 1: kết nối được thiết và có thể gửi tin nhắn giữa client và server.
- 2: kết nối đang được xử lý closing handshake.
- 3: kết nối đang đóng hoặc không thể mở.
- bufferedAmount (read-only): Thể hiện số byte của văn bản UTF-8 đang ở hàng đợi của phương thức send(). Ví dụ dưới đây áp dụng thuộc tính này để đảm bảo tin nhắn được gửi khi buffer chưa đầy:
- protocol (read-only): Trả về sub-protocol được chọn bởi server, xuất hiện từ những protocol được liệt kê trong tham số protocols khi khởi tạo đối tượng
WebSocket
. Trả về chuỗi rỗng nếu kết nối không được thiết lập.
- binaryType: Kiểm soát kiểu dữ liệu nhị phân nhận được từ kết nối
WebSocket
. Có 2 giá trị là blob (giá trị mặc định) và arraybuffer.
3. Socket.IO
3.1 Socket.IO là gì?
Socket.IO
là một thư viện cung cấp kết nối giữa client và server với độ trễ thấp, hai chiều và hoạt động trên hướng sự kiện.Socket.IO is a library that enableslow-latencybidirectionalevent-basedclientserver
Kết nối
Socket.IO
có thể được thiết lập với các phương thức vận chuyển cấp thấp khác nhau:- HTTP long-polling
- WebSocket
- WebTransport
Socket.IO
chọn loại vận chuyển có sẵn hợp lý nhất dựa trên:- Mạng (một số mạng chặn kết nối
WebSocket
hoặc WebTransport)
3.2 Những sai lầm về Socket.IO
Socket.IO không phải là một áp dụng của WebSocket
Mặc dù thực tế
Socket.IO
sẽ sử dụng WebSocket
để vận chuyển khi có thể, nhưng có thêm metadata vào mỗi gói tin. Vì lẽ đó không thể kết nối Socket.IO
client đến WebSocket
server và ngược lại là WebSocket
client đến Socket.IO
server.Lưu ý
Socket.IO
không được dùng cho dịch vụ nền của ứng dụng điện thoại.
- Thư viện
Socket.IO
luôn giữ cho kết nối TCP đến server mở, điều này có thể tiêu thụ nhiều pin cho người dùng.
- Có thể sử dụng nền tảng nhắn tin chuyên dụng như FCM cho trường hợp sử dụng này.
3.3 Tính năng của Socket.IO
Dưới đây là các tính năng được cung cấp bởi
Socket.IO
trên WebSocket
đơn giản:3.3.1 Dự phòng HTTP long-polling
Kết nối sẽ tự động trở về HTTP long-polling trong trường hợp không thể thiết lập kết nối
WebSocket
.Đây là tính năng hàng đầu để người dùng sử dụng
Socket.IO
suốt 10 năm qua khi mà trước đây chưa có nhiều trình duyệt hỗ trợ cho WebSocket
.Ngay cả khi hầu hết các trình duyệt hiện nay đều hỗ trợ
WebSocket
(hơn 97%), đây vẫn là một tính năng tuyệt vời vì chúng tôi vẫn nhận được báo cáo từ người dùng rằng không thể thiết lập kết nối WebSocket
vì họ sử dụng một số proxy bị định cấu hình sai.3.3.2 Tự động kết nối lại
Trong một số điều kiện cụ thể, kết nối
WebSocket
giữa server và client có thể bị gián đoạn mà cả hai bên đều không biết về trạng thái liên kết bị hỏng.Đó là lý do tại sao
Socket.IO
bao gồm cơ chế heartbeat
, kiểm tra định kỳ trạng thái kết nối.Và khi client cuối cùng bị ngắt kết nối, nó sẽ tự động kết nối lại với độ trễ chờ tăng dần theo theo cấp số nhân, để không làm server bị quá tải.
3.3.3 Packet buffering
Các gói được tự động lưu vào bộ đệm khi client bị ngắt kết nối và sẽ được gửi khi kết nối lại.
Mặc dù hữu ích trong hầu hết các trường hợp (khi độ trễ kết nối lại ngắn), nhưng nó có thể dẫn đến một lượng lớn các sự kiện khi kết nối được khôi phục.
Có một số giải pháp để ngăn chặn hành vi này, tùy thuộc vào trường hợp sử dụng của bạn:
- sử dụng thuộc tính
connected
của phiên bản Socket
- sử dụng
volatile events
3.3.4 Acknowledgements
Socket.IO
cung cấp một cách thuận tiện để gửi sự kiện và nhận phản hồi:Sender
Receiver
Có hỗ trợ thêm
Timeout
3.3.5 Broadcasting
Từ phía server, bạn có thể gửi tin nhắn / sự kiện đến tất cả các client hoặc một nhóm client được chỉ định. Ví dụ:
3.3.6 Multiplexing
Những namespaces cho phép bạn phân chia logic của ứng dụng chỉ trong 1 kết nối. Điều này hữu ích cho trường hợp bạn phân quyền admin cho những người dùng được uỷ quyền
4. Tổng kết
Chúng ta đã tìm hiểu về cách
WebSocket
cung cấp một cách tiếp cận hai chiều và liên tục giữa máy khách và máy chủ, là một thay thế hữu ích cho long-polling trong HTML5. WebSocket
mở ra nhiều khả năng mới cho việc phát triển những ứng dụng web hiện đại hai chiều, nhiều người dùng trong thời gian thực.Tuy nhiên, việc sử dụng
WebSocket
cơ bản có thể phức tạp và đầy thách thức. Đó là lý do tại sao thư viện Socket.IO
được tạo ra - để giúp đơn giản hóa việc triển khai và quản lý kết nối WebSocket
với nhiều tính năng nổi bật được hỗ trợ tự động.Socket.IO
không chỉ hỗ trợ WebSocket
mà còn giả lập các sự kiện và nhiều tính năng hữu ích khác như dự phòng kết nối HTTP long polling khi có sự cố với WebSocket
và hỗ trợ kết nối lại cách tự động. Vì thế ngày nay Socket.IO
là một lựa chọn tối ưu trong việc phát triển ứng dụng với WebSocket
trở nên dễ dàng hơn.