首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

反向 Ajax,第 2 部分 WebSocket(1)

反向 Ajax,第 2 部分 WebSocket(1)

先决条件在理想的情况下,如果想最大限度地利用本文,您应该了解 JavaScript 和 Java。本文创建的示例是使用 Google Guice 构建的,Google Guice 是用 Java 编写的依赖项注入框架。要理解本文内容,则需要熟悉依赖项注入框架的概念,比如 Guice、Spring 或 Pico。
要运行本文中的示例,还需要使用最新版的 Maven 和 JDK(参阅 )。
WebSocketsWebSockets 在 HTML5 中出现,是比 Comet 更新的反向 Ajax 技术。WebSockets 支持双向、全双工通信信道,而且许多浏览器(Firefox、Google Chrome 和 Safari)也支持它。连接通过 HTTP 请求(也称为 WebSockets 握手)和一些特殊的标头 (header)。连接一直处于激活状态,您可以用 JavaScript 编写和接收数据,正如您使用原始 TCP 套接字一样。
通过输入 ws:// 或 wss://(在 SSL 上)启动 WebSocket URL。
中的时间轴展示了如何使用 WebSockets 进行通信。HTTP 握手被发送到带有特定标头的服务器。然后,可在 JavaScript 的服务器或客户端上提供某种类型的套接字。可使用该套接字来通过事件处理器异步接收数据。
图 1. 通过 WebSockets 执行反向 Ajax在本文的  中有一个 WebSocket 示例。当您运行该示例时,就会到类似于 清单 1 的输出。它显示了事件如何发生在服务器端上,并立即出现在客户端。当客户端发送一些数据时,服务器将其反映在客户端上。
清单 1. 用 JavaScript 编写的 WebSocket 示例
1
2
3
4
5
6
7
8
9
10
11
[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




通常,在 JavaScript 中使用 WebSockets 的方式与 清单 2 中展示的相同(如果您的浏览器支持它)。
清单 2. JavaScript 客户端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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();




可以发送和接收任何类型的数据。WebSockets 可被看作是 TCP 套接字,因此由客户端和服务器决定要发送的数据类型。这里给出的示例发送的是 JSON 字符串。
在创建了 JavaScript WebSocket 对象后,如果在浏览器的控制台(或 Firebug)深入查看 HTTP 请求中的握手,您应该看到特定于 WebSocket 的包头。清单 3                展示了一个示例。
清单 3. HTTP 请求和响应标头示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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




所有标头都被 WebSocket 握手用来授权和建立长期连接。WebSocket JavaScript 对象还包含两个有用的属性:
ws.url返回 WebSocket 服务器的 URL。ws.readyState返回当前连接状态的值:
  • CONNECTING = 0
  • OPEN = 1
  • CLOSED = 2
在服务器端,处理 WebSockets 时更加复杂。还没有 Java 规范提供支持 WebSockets 的标准方式。要使用 Web 容器(如 Tomcat 或 Jetty)的 WebSockets 功能,则需要将应用程序代码紧密聚集到使您能够访问 WebSockets 功能的特定于容器的库中。
的 websocket 文件夹中的示例使用了 Jetty 的 WebSocket API,因为我们使用的是 Jetty 容器。 展示了 WebSocket 处理器。(本系列的第 3 部分将使用不同的后端 WebSocket API。)
清单 4. Jetty 容器的 WebSocket 处理器
1
2
3
4
5
6
7
public final class ReverseAjaxServlet extends WebSocketServlet {
    @Override
    protected WebSocket doWebSocketConnect(HttpServletRequest request,
                                           String protocol) {
        return [...]
    }
}




使用 Jetty 时,有许多处理 WebSocket 握手的方法。更简单的方法是为 Jetty 的 WebSocketServlet 创建子类并实现 doWebSocketConnect 方法。该方法要求您返回 Jetty 的 WebSocket 接口的一个实例。您需要实现该接口,并返回某种代表 WebSocket 连接的端点。清单 5 提供了一个示例。
清单 5. WebSocket 实现示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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;
    }
}




要向客户端发送消息,只需将该消息写入出站即可,如 清单 6 中所示:
清单 6. 向客户端发送一条消息
1
if (outbound != null && outbound.isOpen()) { outbound.sendMessage('Hello World !'); }




要断开客户端并关闭 WebSocket 连接,可以使用 outbound.disconnect();。
WebSockets 是一种非常强大的实现双向通信的方法,且无延迟,Firefox、Google Chrome、Opera 及其他现代浏览器都支持它。根据 jWebSocket 网站上的调查:
  • Chrome 自 4.0.249 开始便包含本机 WebSockets。
  • Safari 5.x 包括本机 WebSockets。
  • Firefox 3.7a6 和 4.0b1+ 包含本机 WebSockets。
  • Opera 从 10.7.9067 开始便包含本机 WebSockets。
如需关于 jWebSocket 的更多信息,请参阅 。
优势WebSockets 提供强大的、双向、低延迟和易于处理的错误。它没有很多连接,比如:Comet 长轮询,而且也没有 Comet 流的缺点。与 Comet 相比,该 API 易于直接使用,无需使用任何其他层,Comet 需要一个很好的库来处理连接、超时、Ajax 请求、确认以及不同的传输(Ajax 长轮询和 jsonp 轮询)。
缺点WebSockets 的缺点包括:
  • 它是来自 HTML5 的新规范,并不是所有浏览器都支持它。
  • 无请求作用域。由于 WebSockets 是一个 TCP 套接字,而不是一个 HTTP 请求,因此无法轻松使用请求作用域服务,如 Hibernate 的 SessionInViewFilter。Hibernate 是一个持久性框架,提供了一个过滤器来处理 HTTP 请求。请求开始时,将建立一个绑定到请求线程的争用(包含事务和 JDBC 连接)。请求结束后,过滤器会破坏该争用。
返回列表