
Reverse Ajax, Phần 2: WebSockets
WebSockets
WebSockets mới xuất hiện trong HTML5, là một kỹ thuật Reverse Ajax mới hơn Comet.
WebSockets cho phép các kênh giao tiếp song song hai chiều và hiện đã được hỗ trợ trong nhiều
trình duyệt (Firefox, Google Chrome và Safari). Kết nối được mở thông qua một HTTP request
(yêu cầu HTTP), được gọi là liên kết WebSockets với những header đặc biệt. Kết nối được duy
trì để bạn có thể viết và nhận dữ liệu bằng JavaScript như khi bạn đang sử dụng một TCP socket
đơn thuần.
Một URL WebSocket được bắt đầu bằng cách gõ ws:// hoặc wss:// (trên SSL).
Hình 1 cho thấy cách giao tiếp khi sử dụng WebSockets. Một liên kết HTTP được gửi đến máy
chủ với các header cụ thể. Sau đó, một loại socket Javascript có sẵn trên máy chủ hoặc máy
khách sẽ được sử dụng để nhận dữ liệu không đồng bộ thông qua một trình xử lý sự kiện.
Hình 1. Reverse Ajax với WebSockets
Bạn có thể tải về mã nguồn cho bài này. Khi bạn chạy ví dụ này, bạn sẽ thấy kết quả tương tự
như Liệt kê 1. Nó cho thấy các sự kiện đã xảy ra bên phía máy chủ và cũng xuất hiện ngay lập
tức bên phía máy khách như thế nào. Khi máy khách gửi đi dữ liệu nào đó, máy chủ sẽ báo lại
cho máy khách.
Liệt kê 1. Ví dụ mẫu WebSocket bằng JavaScript
[client] WebSocket connection opened
[server] 1 events
[event] ClientID = 0
[server] 1 events
[event] At Fri Jun 17 21:12:01 EDT 2011
[server] 1 events
[event] From 0 : qqq

[server] 1 events
[event] At Fri Jun 17 21:12:05 EDT 2011
[server] 1 events
[event] From 0 : vv
Thông thường, trong JavaScript bạn sẽ sử dụng WebSockets như được trình bày trong Liệt kê 2,
nếu trình duyệt của bạn có hỗ trợ nó.
Liệt kê 2. Mã JavaScript ở máy khách
var ws = new WebSocket('ws://127.0.0.1:8080/async');
ws.onopen = function() {
// called when connection is opened
};
ws.onerror = function(e) {
// called in case of error, when connection is broken in example
};
ws.onclose = function() {
// called when connexion is closed
};
ws.onmessage = function(msg) {
// called when the server sends a message to the client.
// msg.data contains the message.
};
// Here is how to send some data to the server
ws.send('some data');
// To close the socket:
ws.close();
Dữ liệu được gửi và nhận có thể là kiểu bất kỳ nào. Có thể xem WebSockets giống như TCP
socket, vì thế tùy thuộc vào máy khách và máy chủ để biết kiểu dữ liệu nào đang được gửi qua.
Ví dụ ở Liệt kê 2 đang gửi các chuỗi JSON.
Khi một đối tượng Websocket Javascript được tạo ra, nếu xem kỹ các HTTP request trong giao
diện trình duyệt (hoặc Firebug) của lần kết nối đó, bạn sẽ thấy các header đặc trưng của
WebSocket. Liệt kê 3 là một ví dụ.
Liệt kê 3. Ví dụ mẫu về HTTP request và các header phản hồi
Request URL:ws://127.0.0.1:8080/async
Request Method:GET
Status Code:101 WebSocket Protocol Handshake
Request Headers
Connection:Upgrade
Host:127.0.0.1:8080

Origin:http://localhost:8080
Sec-WebSocket-Key1:1 &1~ 33188Yd]r8dp W75q
Sec-WebSocket-Key2:1 7; 229 *043M 8
Upgrade:WebSocket
(Key3):B4:BB:20:37:45:3F:BC:C7
Response Headers
Connection:Upgrade
Sec-WebSocket-Location:ws://127.0.0.1:8080/async
Sec-WebSocket-Origin:http://localhost:8080
Upgrade:WebSocket
(Challenge Response):AC:23:A5:7E:5D:E5:04:6A:B5:F8:CC:E7:AB:6D:1A:39
Các header được dùng trong các liên kết WebSocket để ủy quyền và thiết lập các kết nối long-
lived. Đối tượng WebSocket JavaScript cũng chứa hai đặc tính hữu dụng:
ws.url
Trả về URL của máy chủ WebSocket.
ws.readyState
Trả về giá trị của trạng thái kết nối hiện tại:
CONNECTING = 0
OPEN = 1
CLOSED = 2
Về phía máy chủ, việc xử lý WebSockets phức tạp hơn một chút. Vẫn chưa có đặc tả Java chuẩn
hỗ trợ WebSockets. Để sử dụng các tính năng WebSockets của web container (ví dụ, Tomcat
hoặc Jetty), bạn phải ghép mã ứng dụng với các thư viện đặc thù.
Ví dụ trong thư mục websocket của mã nguồn mẫu sử dụng API WebSocket của Jetty do chúng
tôi đang sử dụng Jetty container. Liệt kê 4 cho thấy trình xử lý WebSocket. (Phần 3 của loạt bài
này sẽ sử dụng các API WebSocket khác nhau cho các tầng bên dưới).
Liệt kê 4. Trình xử lý WebSocket cho một Jetty container
public final class ReverseAjaxServlet extends WebSocketServlet {
@Override
protected WebSocket doWebSocketConnect(HttpServletRequest request,
String protocol) {
return [...]
}
}
Với Jetty, có một số cách để xử lý một liên kết WebSocket. Một cách dễ dàng là phân lớp
WebSocketServlet của Jetty và thực thi phương thức doWebSocketConnect Phương thức này

sẽ yêu cầu bạn trả về một thể hiện của WebSocket interface. Bạn phải thực thi interface này và
trả về một loại thông tin gọi là endpoint đại diện cho liên kết WebSocket. Liệt kê 5 cung cấp một
ví dụ mẫu.
Liệt kê 5. Ví dụ về thực thi WebSocket
class Endpoint implements WebSocket {
Outbound outbound;
@Override
public void onConnect(Outbound outbound) {
this.outbound = outbound;
}
@Override
public void onMessage(byte opcode, String data) {
// called when a message is received
// you usually use this method
}
@Override
public void onFragment(boolean more, byte opcode,
byte[] data, int offset, int length) {
// when a fragment is completed, onMessage is called.
// Usually leave this method empty.
}
@Override
public void onMessage(byte opcode, byte[] data,
int offset, int length) {
onMessage(opcode, new String(data, offset, length));
}
@Override
public void onDisconnect() {
outbound = null;
}
}
Để gửi một thông báo đến máy khách, bạn xuất thông báo ra outbound, như thể hiện trong Liệt
kê 6:
Liệt kê 6. Gửi một thông báo đến máy khách
if (outbound != null && outbound.isOpen()) {
outbound.sendMessage('Hello World !');
}

Để ngắt kết nối máy khách và đóng kết nối WebSocket, hãy sử dụng outbound.disconnect();.
WebSockets là một cách rất mạnh để thực hiện giao tiếp hai chiều mà không có độ trễ nào.
Firefox, Google Chrome, Opera và các trình duyệt hiện đại khác đều hỗ trợ nó. Theo trang web
jWebSocket:
Chrome có WebSockets nguyên gốc kể từ phiên bản 4.0.249.
Safari 5.x có WebSockets nguyên gốc.
Firefox 3.7a6 và 4.0b1+ có WebSockets nguyên gốc.
Opera có WebSockets nguyên gốc kể từ phiên bản 10.7.9067.
Để biết thêm thông tin về jWebSocket, xem phần Tài nguyên.
Ưu điểm
WebSockets cung cấp khả năng giao tiếp hai chiều mạnh mẽ, có độ trễ thấp và dễ xử lý lỗi.
Không cần phải có nhiều kết nối như phương pháp Comet long-polling và cũng không có những
nhược điểm như Comet streaming. API cũng rất dễ sử dụng trực tiếp mà không cần bất kỳ các
tầng bổ sung nào, so với Comet, thường đòi hỏi một thư viện tốt để xử lý kết nối lại, thời gian
chờ timeout, các Ajax request (yêu cầu Ajax), các tin báo nhận và các dạng truyền tải tùy chọn
khác nhau (Ajax long-polling và jsonp polling).
Nhược điểm
Những nhược điểm của WebSockets gồm có:
Nó là một đặc tả mới của HTML5, nên nó vẫn chưa được tất cả các trình duyệt hỗ trợ.
Không có phạm vi yêu cầu nào. Do WebSockets là một TCP socket chứ không phải là
HTTP request, nên không dễ sử dụng các dịch vụ có phạm vi-yêu cầu, như
SessionInViewFilter của Hibernate. Hibernate là một framework kinh điển cung cấp
một bộ lọc xung quanh một HTTP request. Khi bắt đầu một request, nó sẽ thiết lập một
contest (chứa các transaction và liên kết JDBC) được ràng buộc với luồng request. Khi
request đó kết thúc, bộ lọc hủy bỏ contest này.
Về đầu trang
FlashSockets
Đối với các trình duyệt không hỗ trợ WebSockets, một số thư viện có khả năng quay lại
FlashSockets (các socket thông qua Flash). Các thư viện thường cung cấp một API WebSocket
chính thức tương tự, nhưng chúng thực hiện nó bằng cách ủy quyền các cuộc gọi đến một thành
phần Flash ẩn được tích hợp trên trang web.
Ưu điểm

