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

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

Web phần lớn được xây dựng xung quanh mô hình yêu cầu/phản hồi HTTP. Một ứng dụng tải một trang web và sau đó không có gì xảy ra cho đến khi người dùng nhấp vào trang tiếp theo. Khoảng năm 2005, AJAX bắt đầu làm cho trang 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 định hướng. Điều này đòi hỏi người dùng phải tương tác hoặc thăm dò ý kiến đị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 có dữ liệu mới đã được cung cấp từ khá lâu. Chúng có tên như "Push" (Đẩy) hoặc "Comet" (Sao chổi). Một trong những cách tấn công phổ biến nhất để tạo ảo tưởng 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 cuộc thăm dò ý kiến trong thời gian dài, máy khách sẽ mở kết nối HTTP với máy chủ và máy chủ sẽ duy trì kết nối này 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 liên quan đến các yêu cầu Flash, XHR multipart 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 tốn kém cho giao thức HTTP, điều này không làm cho chúng phù hợp với các ứng dụng có độ trễ thấp. Nghĩ đến 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 WebSocket: Đưa ổ cắm đến web

Thông số kỹ thuật WebSocket xác định một API thiết lập 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: Máy khách và máy chủ đã liên tục kết nối với nhau và cả hai bên đều có thể bắt đầu gửi dữ liệu bất cứ lúc nào.

Bắt đầu

Bạn chỉ cần gọi hàm khởi tạo WebSocket là có thể 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 https: được sử dụng 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 cho phé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 con đã chuyể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 Danh sách đăng ký IANA. Hiện chỉ có một tên giao thức phụ (xà phòng) được đăng ký vào 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 sau khi 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, phương thức này chỉ hỗ trợ các chuỗi, nhưng trong thông số kỹ thuật mới nhất, phương thức này hiện cũng có thể gửi các tin nhắn 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 cứ 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 một đối tượng sự kiện và thông báo thực tế có thể truy cập được 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, hãy đặt thuộc tính binaryType của đối tượng WebSocket thành "blob" hoặc "arraybuffer". Định dạng mặc định là "blob". (Bạn không cần 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à các tiện ích. Khi sử dụng tiện ích, bạn có thể gửi các khung nén, được ghép kênh, 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ố tiện ích nào được xuất bản chính thức.

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

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

Là một giao thức hiện đại, hoạt động giao tiếp trên nhiều nguồn gốc được đưa vào WebSocket. Mặc dù bạn vẫn nên đảm bảo chỉ giao tiếp với các ứng dụng và máy chủ mà bạn 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ủ quyết định cung cấp dịch vụ cho tất cả ứng dụng hay chỉ những ứng dụng nằm trên một nhóm 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 loạt những vấn đề mới. Trong trường hợp của WebSocket, đó là khả năng tương thích với các máy chủ proxy có chức năng 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 điều này và sẽ ngắt kết nối. Do đó, ngay cả khi một ứng dụng nhất định sử dụng giao thức WebSocket, bạn 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 trở nê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 tất cả các 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. Thư viện này đi kèm với phương thức triển khai giao thức ứng dụng và máy chủ, đồng thời có các phương án dự phòng (socket.io chưa hỗ trợ thông báo nhị phân kể từ Februrary 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 ứng dụng khách. Do yêu cầu HTTP bổ sung sẽ luôn phát sinh thêm chi phí so với WebSocket đơn thuần.

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 (chẳng hạn như LAMP) được thiết kế xoay quanh chu kỳ yêu cầu/phản hồi HTTP, nhưng thường không xử lý tốt số lượng lớn các kết nối WebSocket mở. Việc duy trì một số lượng lớn kết nối mở cùng một lúc đòi hỏi một cấu trúc nhận được mô hình đồng thời cao với chi phí hiệu suất thấp. Những cấu trúc như vậy thường được thiết kế xoay quanh việc phân luồng hoặc gọi là IO không tuần tự.

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 máy khách và máy chủ) cho WebSocket hiện là RFC6455. Chrome và Chrome mới nhất dành cho Android hoàn toàn tương thích với RFC6455, bao gồm cả tính năng nhắn tin nhị phân. Ngoài ra, Firefox sẽ tương thích trên phiên bản 11, Internet Explorer trên phiên bản 10. Bạn vẫn có thể sử dụng các phiên bản giao thức cũ, nhưng không nên vì chúng dễ bị tấn công. Nếu đã triển khai máy chủ cho các phiên bản giao thức WebSocket cũ hơn, bạn nên nâng cấp 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 quá trình này có thể đòi hỏi bạn phải xem xét lại cách xây dựng các ứng dụng phía máy chủ theo hướng mới, tập trung vào các công nghệ như hàng đợi sự kiện. Sau đâ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 trong Chat
  • Khu vực 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