Giới thiệu WebSockets – Đưa ổ cắm lên web

Vấn đề: Kết nối máy khách-máy khách và máy khách-máy chủ có độ trễ thấp

Web được xây dựng phần lớn dựa trên mô hình yêu cầu/phản hồi của HTTP. Một khách hàng tải một trang web lên rồi không có gì xảy ra cho đến khi người dùng nhấp vào trang tiếp theo. Vào khoảng năm 2005, AJAX bắt đầu làm cho môi trường web trở nên năng động hơn. Tuy nhiên, tất cả hoạt động giao tiếp HTTP đều do máy khách kiểm soát, vốn đòi hỏi người dùng phải tương tác hoặc thăm dò định kỳ để tải dữ liệu mới từ máy chủ.

Các công nghệ cho phép máy chủ gửi dữ liệu đến máy khách ngay khi máy chủ biết rằng dữ liệu mới có sẵn đã được sử dụng được khá lâu. Chúng được đặt theo các tên như "Đẩy" hoặc "Sao chổi". Một trong những thủ thuật phổ biến nhất nhằm tạo ảo giác về kết nối do máy chủ khởi tạo được gọi là thăm dò ý kiến trong thời gian dài. Với chế độ thăm dò dài, máy khách sẽ mở kết nối HTTP đến máy chủ. Kết nối này luôn mở cho đến khi gửi phản hồi. Bất cứ khi nào máy chủ thực sự có dữ liệu mới, máy chủ sẽ gửi phản hồi (các kỹ thuật khác bao gồm yêu cầu Flash, nhiều phần XHR và được gọi là htmlfiles). Cuộc thăm dò ý kiến dài và các kỹ thuật khác hoạt động khá tốt. Bạn sử dụng chúng mỗi ngày trong các ứng dụng như trò chuyện trong Gmail.

Tuy nhiên, tất cả các giải pháp này đều có chung một vấn đề: Chúng gây ra hao tổn của HTTP nên không phù hợp với các ứng dụng có độ trễ thấp. Hãy nghĩ đến các trò chơi bắn súng góc nhìn thứ nhất nhiều người chơi trong trình duyệt hoặc bất kỳ trò chơi trực tuyến nào khác có thành phần theo thời gian thực.

Giới thiệu về WebSocket: Đưa ổ cắm lên web

Thông số kỹ thuật WebSocket xác định một API thiết lập các kết nối "ổ cắm" giữa trình duyệt web và máy chủ. Nói một cách đơn giản: Có một kết nối liên tục giữa máy khách và máy chủ và cả hai bên có thể bắt đầu gửi dữ liệu bất kỳ lúc nào.

Bắt đầu

Bạn chỉ cần gọi hàm khởi tạo WebSocket để mở kết nối WebSocket:

var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);

Hãy lưu ý ws:. Đây là giản đồ URL mới cho các kết nối WebSocket. Ngoài ra, còn có wss: để kết nối WebSocket bảo mật giống như cách dùng https: cho các kết nối HTTP bảo mật.

Việc đính kèm ngay một số trình xử lý sự kiện vào kết nối giúp bạn biết khi nào kết nối được mở, nhận được tin nhắn đến hoặc có lỗi.

Đối số thứ hai chấp nhận các giao thức phụ không bắt buộc. Đó có thể là một chuỗi hoặc một mảng chuỗi. Mỗi chuỗi phải đại diện cho một tên giao thức phụ và máy chủ chỉ chấp nhận một trong các giao thức phụ đã được truyền trong mảng. Bạn có thể xác định giao thức phụ được chấp nhận bằng cách truy cập vào thuộc tính protocol của đối tượng WebSocket.

Tên giao thức phụ phải là một trong các tên giao thức phụ đã đăng ký trong sổ đăng ký IANA. Hiện chỉ có một tên giao thức phụ (xà phòng) được đăng ký tính đến tháng 2 năm 2012.

// When the connection is open, send some data to the server
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};

// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};

// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};

Giao tiếp với máy chủ

Ngay khi có kết nối với máy chủ (khi sự kiện open được kích hoạt), chúng ta có thể bắt đầu gửi dữ liệu đến máy chủ bằng phương thức send('your message') trên đối tượng kết nối. Trước đây, mã này chỉ hỗ trợ các chuỗi, nhưng trong thông số kỹ thuật mới nhất, mã này hiện cũng có thể gửi các thông báo nhị phân. Để gửi dữ liệu nhị phân, bạn có thể sử dụng đối tượng Blob hoặc ArrayBuffer.

// Sending String
connection.send('your message');

// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i];
}
connection.send(binary.buffer);

// Sending file as Blob
var file = document.querySelector('input[type="file"]').files[0];
connection.send(file);

Tương tự như vậy, máy chủ có thể gửi thông báo cho chúng tôi bất kỳ lúc nào. Bất cứ khi nào điều này xảy ra, lệnh gọi lại onmessage sẽ kích hoạt. Lệnh gọi lại nhận được đối tượng sự kiện và có thể truy cập thông báo thực tế thông qua thuộc tính data.

WebSocket cũng có thể nhận thông báo nhị phân trong thông số kỹ thuật mới nhất. Khung nhị phân có thể được nhận ở định dạng Blob hoặc ArrayBuffer. Để chỉ định định dạng của tệp nhị phân nhận được, hãy đặt thuộc tínhBinaryType của đối tượng WebSocket thành "blob" hoặc "arraybuffer". Định dạng mặc định là "blob". (Bạn không phải căn chỉnh tham số binaryType khi gửi.)

// Setting binaryType to accept received binary as either 'blob' or 'arraybuffer'
connection.binaryType = 'arraybuffer';
connection.onmessage = function(e) {
console.log(e.data.byteLength); // ArrayBuffer object if binary
};

Một tính năng mới khác của WebSocket là tiện ích. Khi sử dụng tiện ích, bạn sẽ có thể gửi khung nén, đa thành phần, v.v. Bạn có thể tìm thấy các tiện ích được máy chủ chấp nhận bằng cách kiểm tra thuộc tính tiện ích của đối tượng WebSocket sau sự kiện mở. Kể từ tháng 2 năm 2012, chưa có thông số kỹ thuật tiện ích được xuất bản chính thức nào.

// Determining accepted extensions
console.log(connection.extensions);

Giao tiếp trên nhiều nguồn gốc

Là một giao thức hiện đại, giao tiếp giữa nhiều nguồn gốc được tích hợp ngay vào WebSocket. Mặc dù bạn vẫn phải đảm bảo chỉ giao tiếp với máy khách và máy chủ mà mình tin tưởng, WebSocket cho phép giao tiếp giữa các bên trên bất kỳ miền nào. Máy chủ sẽ quyết định cung cấp dịch vụ cho tất cả khách hàng hay chỉ những khách hàng lưu trú trên một tập hợp miền được xác định rõ.

Máy chủ proxy

Mỗi công nghệ mới đều đi kèm với một nhóm vấn đề mới. Đối với WebSocket thì đó là khả năng tương thích với máy chủ proxy, có vai trò dàn xếp các kết nối HTTP trong hầu hết các mạng của công ty. Giao thức WebSocket sử dụng hệ thống nâng cấp HTTP (thường được sử dụng cho HTTP/SSL) để 'nâng cấp' kết nối HTTP lên kết nối WebSocket. Một số máy chủ proxy không thích tính năng này và sẽ làm mất kết nối. Do đó, ngay cả khi một ứng dụng cụ thể sử dụng giao thức WebSocket thì vẫn có thể không thiết lập được kết nối. Điều này làm cho phần tiếp theo thậm chí còn quan trọng hơn :)

Sử dụng WebSockets ngay hôm nay

WebSocket vẫn là một công nghệ còn non trẻ và chưa được triển khai đầy đủ trong mọi trình duyệt. Tuy nhiên, bạn có thể sử dụng WebSocket ngay hôm nay với các thư viện sử dụng một trong các phương án dự phòng nêu trên bất cứ khi nào WebSocket không có sẵn. Một thư viện đã trở nên rất phổ biến trong miền này là socket.io đi kèm với một ứng dụng khách và một máy chủ triển khai giao thức, đồng thời có cả các bản dự phòng (socket.io chưa hỗ trợ thông báo nhị phân kể từ tháng 1 năm 2012). Ngoài ra, còn có các giải pháp thương mại như PusherApp có thể dễ dàng tích hợp vào bất kỳ môi trường web nào bằng cách cung cấp API HTTP để gửi thông báo WebSocket cho khách hàng. Do yêu cầu HTTP bổ sung, sẽ luôn có mức hao tổn cao hơn so với WebSocket thuần tuý.

Phía máy chủ

Việc sử dụng WebSocket tạo ra một mẫu sử dụng hoàn toàn mới cho các ứng dụng phía máy chủ. Mặc dù các ngăn xếp máy chủ truyền thống như LAMP được thiết kế xoay quanh chu kỳ yêu cầu/phản hồi HTTP, nhưng các ngăn xếp này thường không xử lý tốt với một số lượng lớn kết nối WebSocket mở. Việc đảm bảo một số lượng lớn các kết nối mở cùng lúc đòi hỏi một kiến trúc có tính đồng thời cao với chi phí hiệu suất thấp. Các kiến trúc như vậy thường được thiết kế xung quanh luồng hoặc được gọi là IO không chặn.

Triển khai phía máy chủ

Phiên bản giao thức

Giao thức dây (bắt tay và chuyển dữ liệu giữa ứng dụng và máy chủ) cho WebSocket hiện là RFC6455. Chrome và Chrome dành cho Android mới nhất hoàn toàn tương thích với RFC6455, bao gồm cả thông báo nhị phân. Ngoài ra, Firefox sẽ tương thích trên phiên bản 11, Internet Explorer phiên bản 10. Bạn vẫn có thể sử dụng các phiên bản giao thức cũ hơn nhưng không nên sử dụng vì các phiên bản này được xác định là dễ bị tấn công. Nếu đã triển khai máy chủ cho phiên bản cũ hơn của giao thức WebSocket, bạn nên nâng cấp giao thức này lên phiên bản mới nhất.

Trường hợp sử dụng

Sử dụng WebSocket bất cứ khi nào bạn cần độ trễ thực sự thấp, gần như kết nối theo thời gian thực giữa ứng dụng và máy chủ. Xin lưu ý rằng việc này có thể bao gồm việc xem xét lại cách bạn xây dựng ứng dụng phía máy chủ với trọng tâm mới là các công nghệ như hàng đợi sự kiện. Dưới đây là một số ví dụ về trường hợp sử dụng:

  • Trò chơi trực tuyến nhiều người chơi
  • Ứng dụng Chat
  • Kênh thể thao trực tiếp
  • Cập nhật luồng trên mạng xã hội theo thời gian thực

Bản thu thử

Tài liệu tham khảo