使用 HTML5 WebSocket 构建实时 Web 应用:http://www.ibm.com/developerworks/cn/web/1112_huangxa_websocket/
Web 应用的即时通讯有几种技术:
轮询:
最早的实时 Web 应用的方案。客户端以一定的时间间隔向服务端发出请求,以频繁请求的方式来保持客户端和服务器端的同步。
这种方案的最大问题是,当客户端以固定频率向服务器发起请求的时候,服务器端的数据可能并没有更新,这样会带来很多无谓的网络传输,所以这是一种非常低效的实时方案。
长轮询:
长轮询是对定时轮询的改进和提高,目地是为了降低无效的网络传输。当服务器端没有数据更新的时候,连接会保持一段时间周期直到数据或状态改变或者时间过期,通过这种机制来减少无效的客户端和服务器间的交互。当然,如果服务端的数据变更非常频繁的话,这种机制和定时轮询比较起来没有本质上的性能的提高。
流:
流技术方案就是在客户端的页面使用一个隐藏的窗口向服务端发出一个长连接的请求。服务器端接到这个请求后作出回应并不断更新连接状态以保证客户端和服务器端的连接不过期。
通过这种机制可以将服务器端的信息源源不断地推向客户端。这种机制在用户体验上有一点问题,需要针对不同的浏览器设计不同的方案来改进用户体验,同时这种机制在并发比较大的情况下,对服务器端的资源是一个极大的考验。
目前这些所使用的所谓的实时技术并不是真正的实时技术,它们只是在用 Ajax 方式来模拟实时的效果,在每次客户端和服务器端交互的时候都是一次 HTTP 的请求和应答的过程,而每一次的 HTTP 请求和应答都带有完整的 HTTP 头信息,这就增加了每次传输的数据量,而且这些方案中客户端和服务器端的编程实现都比较复杂,在实际的应用中,为了模拟比较真实的实时效果,开发人员往往需要构造两个 HTTP 连接来模拟客户端和服务器之间的双向通讯,一个连接用来处理客户端到服务器端的数据传输,一个连接用来处理服务器端到客户端的数据传输,这不可避免地增加了编程实现的复杂度,也增加了服务器端的负载,制约了应用系统的扩展性。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
WebSocket 连接本质上就是一个 TCP 连接,所以在数据传输的稳定性和数据传输量的大小方面,和轮询以及 Comet 技术比较,具有很大的性能优势。
WebSocket 规范
为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息”Upgrade: WebSocket”表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道*的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。
下面我们来详细介绍一下 WebSocket 规范,由于这个规范目前还是处于草案阶段,版本的变化比较快,我们选择 draft-hixie-thewebsocketprotocol-76版本来描述 WebSocket 协议。因为这个版本目前在一些主流的浏览器上比如 Chrome,、FireFox、Opera 上都得到比较好的支持,您如果参照的是新一些的版本话,内容可能会略有差别。
一个典型的 WebSocket 发起请求和得到响应的例子看起来如下:
清单 1. WebSocket 握手协议
客户端到服务端: GET /demo HTTP/1.1 Host: example.com Connection: Upgrade Sec-WebSocket-Key2: 12998 5 Y3 1 .P00 Upgrade: WebSocket Sec-WebSocket-Key1: 4@1 46546xW%0l 1 5 Origin: http://example.com [8-byte security key] 服务端到客户端: HTTP/1.1 101 WebSocket Protocol Handshake Upgrade: WebSocket Connection: Upgrade WebSocket-Origin: http://example.com WebSocket-Location: ws://example.com/demo [16-byte hash response]
Upgrade:WebSocket
表示这是一个特殊的 HTTP 请求
目的是要将客户端和服务器端的通讯协议从 HTTP 协议升级到 WebSocket 协议。
Sec-WebSocket-Key1、Sec-WebSocket-Key2、[8-byte securitykey]
这是客户端浏览器需要向服务器端提供的握手信息,服务器端解析这些头信息,并在握手的过程中依据这些信息生成一个 16 位的安全密钥并返回给客户端,以表明服务器端获取了客户端的请求,同意创建 WebSocket 连接。一旦连接建立,客户端和服务器端就可以通过这个通道双向传输数据了。
为了使用 WebSocket 接口构建 Web 应用,首先需要构建一个实现了 WebSocket 规范的服务器。
服务器端的实现不受平台和开发语言的限制。
只需要遵从 WebSocket 规范即可。
目前已经出现了一些比较成熟的 WebSocket 服务器端实现,比如:
1.Kaazing WebSocket Gateway — 一个 Java 实现的 WebSocket Server
2.mod_pywebsocket — 一个 Python 实现的 WebSocket Server
3.Netty —一个 Java 实现的网络框架其中包括了对 WebSocket 的支持
4.node.js —一个 Server 端的 JavaScript 框架提供了对 WebSocket 的支持
- 如果以上的 WebSocket 服务端实现还不能满足您的业务需求的话,开发人员完全可以根据 WebSocket 规范自己实现一个服务器。
-
WebSocket JavaScript 接口
握手协议是在构建 WebSocket 服务器端的实现和提供浏览器的 WebSocket 支持时需要考虑的问题。
针对 Web 开发人员的 WebSocket JavaScript 客户端接口非常简单,以下是 WebSocket JavaScript 接口的定义:
清单 2. WebSocket JavaScript 定义
[Constructor(in DOMString url, in optional DOMString protocol)] interface WebSocket { readonly attribute DOMString URL; // ready state const unsigned short CONNECTING = 0; const unsigned short OPEN = 1; const unsigned short CLOSED = 2; readonly attribute unsigned short readyState; readonly attribute unsigned long bufferedAmount; //networking attribute Function onopen; attribute Function onmessage; attribute Function onclose; boolean send(in DOMString data); void close(); }; WebSocket implements EventTarget;
URL --- WebSocket 服务器的网络地址
ws --- 协议
send 方法 --- 发送数据到服务器端
close 方法 --- 关闭连接
事件:
onopen
onmessage
onerror
onclose
借用 Nettuts 网站上的一张图来形象的展示一下 WebSocket 接口:
下面是一段简单的 JavaScript 代码展示了怎样建立 WebSocket 连接和获取数据:
清单 3. 建立 WebSocket 连接的实例 JavaScript 代码
var wsServer = ‘ws://localhost:8888/Demo‘; var websocket = new WebSocket(wsServer); websocket.onopen = function (evt) { onOpen(evt) }; websocket.onclose = function (evt) { onClose(evt) }; websocket.onmessage = function (evt) { onMessage(evt) }; websocket.onerror = function (evt) { onError(evt) }; function onOpen(evt) { console.log("Connected to WebSocket server."); } function onClose(evt) { console.log("Disconnected"); } function onMessage(evt) { console.log(‘Retrieved data from server: ‘ + evt.data); } function onError(evt) { console.log(‘Error occured: ‘ + evt.data); }
浏览器支持
下面是主流浏览器对 HTML5 WebSocket 的支持情况:
浏览器 | 支持情况 |
Chrome | Supported in version 4+ |
Firefox | Supported in version 4+ |
Internet Explorer | Supported in version 10+ |
Opera | Supported in version 10+ |
Safari | Supported in version 5+ |