1. Trang chủ
  2. » Công Nghệ Thông Tin

Reverse Ajax, Phần 2: WebSockets potx

12 491 2
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Reverse ajax, phần 2: Websockets
Trường học University of Information Technology
Chuyên ngành Computer Science
Thể loại bài viết
Năm xuất bản 2025
Thành phố Ho Chi Minh City
Định dạng
Số trang 12
Dung lượng 285,72 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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.. Khi một đối tượng Websocket Javasc

Trang 1

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

Trang 2

[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

Trang 3

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

Trang 4

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 !');

}

Trang 5

Để 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

Trang 6

FlashSockets cung cấp tính năng WebSockets một cách trong suốt, ngay cả trên các trình duyệt không hỗ trợ WebSockets của HTML5

Nhược điểm

FlashSockets có những nhược điểm sau đây:

 Cần phải cài thêm Flash plug-in (thường thì tất cả các trình duyệt đều có sẵn)

 Cần phải mở port 843 trong tường lửa để cho thành phần Flash có thể thực hiện một HTTP request để lấy ra một tệp chính sách có chứa thông tin ủy quyền

Nếu không thể thông qua được port 843, thư viện cần quay trở lại hoặc đưa ra một lỗi Tất cả quá trình xử lý này đều mất thời gian (nhiều nhất lên đến 3 giây, tùy thuộc vào thư viện), sẽ làm chậm trang web

 Nếu máy khách có sử dụng proxy, thì có thể kết nối tới port 843 sẽ bị từ chối

Dự án WebSocketJS có thể giúp hỗ trợ WebSockets cho các trình duyệt Firefox 3, Internet Explorer 8 và Internet Explorer 9, tuy nhiên nó yêu cầu phải cài đặt Flash từ bản 10 trở đi Khuyến cáo

So với Comet, WebSockets mang lại nhiều lợi ích hơn và ngày càng được phát triển để nhanh chóng hỗ trợ trên máy khách và tạo ra ít request hơn (do đó phương pháp này tiêu thụ ít băng thông hơn) Tuy nhiên, do không phải tất cả các trình duyệt đều đang hỗ trợ WebSockets, nên tốt nhất khi sử dụng kỹ thuật Reverse Ajax là ta sẽ thêm một tính năng giúp phát hiện xem

WebSocket có được hỗ trợ hay không, nếu không thì chuyển sang phương pháp Comet (long-polling)

Do hai kỹ thuật này là cần thiết để nhận được sự lựa chọn tốt nhất trong tất cả các trình duyệt và duy trì tính tương thích, nên điều quan trọng là bạn sử dụng một thư viện JavaScript máy khách, cung cấp một tầng trừu tượng dựa trên các kỹ thuật này Phần 3 và Phần 4 của loạt bài này sẽ tìm hiểu một số thư viện và Phần 5 sẽ cho bạn thấy cách ứng dụng chúng Về phía máy chủ, những việc này đều phức tạp hơn một chút, như được thảo luận trong phần tiếp theo

Về đầu trang

Các ràng buộc Reverse Ajax ở phía máy chủ

Bây giờ bạn có một tổng quan về các giải pháp Reverse Ajax có sẵn bên phía máy khách, chúng

ta hãy tìm hiểu các giải pháp Reverse Ajax trên máy chủ Cho tới giờ thì các ví dụ trong bài chỉ được sử dụng chủ yếu trên máy khách Về phía máy chủ, để chấp nhận các kết nối Reverse Ajax, một số kỹ thuật yêu cầu các tính năng đặc trưng để xử lý các kết nối long-lived so với các HTTP request ngắn mà bạn đã quen thuộc Để có thể linh động hơn, ta nên sử dụng một mô hình luồng mới, nó đòi hỏi phải có một API Java đặc trưng để có thể tạm dừng các yêu cầu Ngoài ra, đối với WebSockets, bạn phải quản lý đúng phạm vi của các dịch vụ được dùng trong ứng dụng

Trang 7

I/O threading và I/O non-blocking

Thông thường, một máy chủ web liên kết một luồng hoặc một quá trình cho mỗi kết nối HTTP đến Kết nối này có thể tồn tại lâu bền (được duy trì) sao cho một số yêu cầu đi qua cùng một kết nối Trong ví dụ của bài này, có thể cấu hình máy chủ web Apache theo các mô hình mpm_fork hoặc mpm_worker để thay đổi hành vi này Các máy chủ Java web (bao gồm cả các máy chủ ứng dụng tương tự) thường sử dụng một luồng cho mỗi kết nối đến

Việc sinh ra một luồng mới dẫn đến việc tiêu thụ bộ nhớ và lãng phí tài nguyên vì nó không đảm bảo sẽ sử dụng luồng mới được sinh ra Kết nối có thể thiết lập được, nhưng không có dữ liệu nào từ máy khách hoặc máy chủ được gửi đi Cho dù có sử dụng luồng này hay không, thì nó vẫn tiêu thụ bộ nhớ và tài nguyên CPU cho việc lập lịch trình và các khóa chuyển đổi contest Và, khi cấu hình một máy chủ bằng cách sử dụng một mô hình luồng, bạn thường phải cấu hình một nhóm luồng (thiết lập một số lượng tối đa các luồng để xử lý các kết nối đến) Nếu giá trị này bị cấu hình sai và quá thấp, bạn sẽ kết thúc bằng một vấn đề thiếu luồng; các yêu cầu sẽ chờ cho đến khi có một luồng khác để xử lý chúng Thời gian đáp ứng sẽ chậm khi đạt được kết nối tối đa đồng thời Mặt khác, việc cấu hình một giá trị cao có thể dẫn đến một trường hợp ngoại lệ là thiếu bộ nhớ Việc sinh ra quá nhiều luồng sẽ tiêu thụ tất cả các kích cỡ heap (vùng lưu trữ đặc biệt trong bộ nhớ) của JVM và dẫn đến sự cố cho máy chủ

Gần đây Java đã giới thiệu một API I/O (API vào/ra) mới được gọi là I/O non-blocking API này

sử dụng một bộ lựa chọn để tránh ràng buộc với một luồng mỗi khi thực hiện một kết nối HTTP tới máy chủ Khi dữ liệu đến, một sự kiện được thu nhận và một luồng được cấp phát để xử lý yêu cầu Như vậy, việc này được gọi là một mô hình luồng cho mỗi yêu cầu Nó cho phép các máy chủ web, chẳng hạn như WebSphere và Jetty, điều chỉnh co giãn và xử lý một số lượng lớn các kết nối người dùng gia tăng với một số luồng cố định Với cùng một cấu hình phần cứng, các máy chủ web đang chạy trong chế độ này điều chỉnh co giãn tốt hơn nhiều so với ở chế độ luồng cho mỗi kết nối

Trong blog của mình, Philip McCarthy (tác giả của Comet and Reverse Ajax) có một đánh giá

thú vị về khả năng điều chỉnh co giãn của hai mô hình luồng (xem phần Tài nguyên để thấy liên kết tới bài viết) Trong Hình 2 bạn sẽ thấy một mẫu tương tự: một mô hình luồng ngừng làm việc với quá nhiều các kết nối

Trang 8

Hình 2 Đánh giá về các mô hình luồng

Mô hình luồng cho mỗi kết nối (đường Threads trong Hình 2) thường có thời gian đáp ứng tốt hơn, do tất cả các luồng đã thiết lập, sẵn sàng và chờ đợi, nhưng nó dừng phục vụ khi số lượng kết nối quá cao Trong mô hình luồng cho mỗi yêu cầu (đường Continuations trong Hình 2), một luồng được sử dụng để phục vụ yêu cầu đến và kết nối được xử lý thông qua một bộ lựa chọn NIO Thời gian đáp ứng có thể chậm hơn một chút, nhưng vì các luồng được sử dụng lại nên giải pháp này co giãn tốt hơn với nhiều kết nối

Để hiểu đằng sau việc tạo các luồng ra sao, hãy tưởng tượng một khối LEGO™ như là bộ lựa chọn Mỗi kết nối đến đi tới khối LEGO này và được xác định bằng một chân Khối LEGO/bộ lựa chọn sẽ có nhiều chân (nhiều khóa) như các kết nối Sau đó, chỉ có một luồng cần thiết để lặp lại qua các chân khi nó chờ các sự kiện mới xảy ra Khi có một điều gì đó xảy ra, luồng của bộ lựa chọn sẽ lấy ra các khóa dùng cho các sự kiện đã xảy ra và một luồng có thể được sử dụng để phục vụ yêu cầu đến

"Hướng dẫn Rox Java NIO" là ví dụ về việc sử dụng NIO trong Java (xem phần Tài nguyên)

Về đầu trang

Các dịch vụ phạm vi-yêu cầu

Nhiều framework cung cấp các dịch vụ hoặc các bộ lọc, xử lý một yêu cầu web đến trong một servlet Ví dụ, một bộ lọc sẽ:

 Ràng buộc một kết nối JDBC đến một luồng yêu cầu sao cho chỉ có một kết nối được sử dụng cho toàn bộ yêu cầu

Trang 9

 Cam kết các thay đổi vào cuối mỗi yêu cầu

Một ví dụ khác là phần mở rộng Guice Servlet của Google Guice (một thư viện dependency injection) Giống như Spring, Guice có thể kết buộc các dịch vụ trong một phạm vi yêu cầu Một

cá thể sẽ được tạo ra nhiều nhất là một lần cho mỗi yêu cầu mới (xem phần Tài nguyên để biết thêm thông tin)

Cách sử dụng điển hình sẽ gồm lưu trữ trong bộ nhớ đệm một đối tượng người dùng được lấy ra

từ một kho lưu trữ (ví dụ, một cơ sở dữ liệu) theo yêu cầu bằng cách sử dụng id (mã định danh) của người dùng được lấy từ vùng session HTTP Trong Google Guice, bạn có thể có mã tương tự như Liệt kê 7

Liệt kê 7 Ràng buộc có phạm vi-yêu cầu

@Provides

@RequestScoped

Member member(AuthManager authManager,

MemberRepository memberRepository) {

return memberRepository.findById(authManager.getCurrentUserId());

}

Khi một thành viên được tích hợp vào trong một lớp, Guice sẽ cố gắng tìm nạp nó từ yêu cầu đó Nếu không tìm thấy, nó sẽ thực hiện cuộc gọi kho lưu trữ và giao kết quả cho yêu cầu đó

Có thể sử dụng các dịch vụ phạm vi-yêu cầu với bất kỳ giải pháp Reverse Ajax nào trừ

WebSockets Bất kỳ giải pháp khác nào dựa trên các HTTP request ngắn hoặc long-lived, nên mỗi yêu cầu thường có hệ thống gửi servlet và các bộ lọc được thực thi Khi tạm dừng một HTTP request (long-lived), bạn sẽ thấy trong các phần tiếp theo của loạt bài này cũng có một tùy chọn để thực hiện yêu cầu thông qua chuỗi bộ lọc lại

Đối với WebSockets, dữ liệu trực tiếp đi tới sự kiện onMessage, giống như trong một TCP socket Do vẫn không có bất kỳ HTTP request nào gửi dữ liệu này đến, nên không có yêu cầu contest nào mà từ đó có thể nhận và lưu trữ các đối tượng có phạm vi Như vậy, việc sử dụng các dịch vụ yêu cầu các đối tượng có phạm vi từ một sự kiện onMessage sẽ thất bại

Ví dụ mẫu guice và websocket trong mã nguồn cho thấy cách vượt qua hạn chế và vẫn sử dụng các đối tượng có phạm vi-yêu cầu trong một sự kiện onMessage Khi bạn chạy ví dụ mẫu này và nhấn vào từng button trên trang web để kiểm tra một cuộc gọi Ajax (có phạm vi-yêu cầu) và một cuộc gọi WebSocket Một cuộc gọi WebSocket có một yêu cầu mô phỏng được quy định phạm

vi, bạn sẽ nhận được kết quả như trong Hình 3

Hình 3 Kết quả của một trình xử lý WebSocket khi sử dụng các dịch vụ có phạm vi-yêu

Trang 10

cầu

Bạn có thể gặp các vấn đề như vậy khi bạn dùng:

 Spring

 Hibernate

 Bất kỳ framework khác nào đòi hỏi mô hình có phạm vi-yêu cầu hoặc một mô hình cho mỗi yêu cầu, chẳng hạn như OpenSessionInViewFilter

 Bất kỳ hệ thống nào đang sử dụng phương tiện ThreadLocal để quy định phạm vi các biến cho một luồng yêu cầu trong một bộ lọc và truy cập chúng sau này

Guice có độ phân giải đẹp, như thể hiện trong Liệt kê 8:

Liệt kê 8 Mô phỏng một phạm vi-yêu cầu từ sự kiện onMessage của WebSocket

// The reference to the request is hold when the

// doWebSocketMethod is called

HttpServletRequest request = [ ]

Map<Key<?>, Object> bindings = new HashMap<Key<?>, Object>();

// I have a service which needs a request to get the session,

// so I provide the request, but you could provide any other

// binding that may be needed

bindings.put(Key.get(HttpServletRequest.class), request);

ServletScopes.scopeRequest(new Callable<Object>() {

@Override

public Object call() throws Exception {

// call your repository or any service using the scoped objects outbound.sendMessage([ ]);

return null;

}

}, bindings).call();

Ngày đăng: 09/03/2014, 04:20

HÌNH ẢNH LIÊN QUAN

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ể - Reverse Ajax, Phần 2: WebSockets potx
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ể (Trang 1)
Hình 2. Đánh giá về các mô hình luồng - Reverse Ajax, Phần 2: WebSockets potx
Hình 2. Đánh giá về các mô hình luồng (Trang 8)