这两年中,HTML5发展的如火如荼,再不学习一下,觉得自己都落后了。说到HTML5,最让我惊心动魄的特性我觉得就是全新的WebSocket通信协议了。有"Web通信TCP"之称的 WebSocket的出现使得浏览器提供对 Socket 的支持成为可能,从而在浏览器和服务器之间提供了一个基于TCP连接的双向通道。Web开发人员可以非常方便地使用WebSocket构建实时web应用。
Web的交互过程
这种机制对于信息变化不是特别频繁的应用尚能相安无事,但是对于那些实时要求比较高的应用来说(比如说在线游戏),当客户端浏览器准备呈现获取到的信息的时候,这些信息在服务器端可能已经过时了,所以保持客户端和服务器端的信息同步是实时 Web 应用的关键要素。在WebSocket规范出来之前,开发人员想实现这种应用,不得不采用一些折衷的方案,其中最常用的就是轮询 (Polling) 和 Comet(轮询的改进版本,又可细分为长轮询机制与流技术) 技术。这几种方案,基本都是在用 Ajax 方式来模拟实时的效果,服务器与客户端编程都比较复杂,而且效率不高。
HTML5 WebSocket设计出来的目的就是要取代轮询和Comet技术,使客户端浏览器具备像C/S架构下桌面系统的实时通讯能力。 浏览器向服务器发出建立WebSocket连接的请求,连接建立以后,客户端和服务器端就可以通过TCP连接直接交换数据。因为WebSocket连接本质上就是一个TCP连接,所以在数据传输的稳定性和数据传输量的大小方面,和轮询以及Comet技术比较,具有很大的性能优势。这种统计数据在网上很多,这里我选了一幅图,只能说我看到对比数据时,当场震惊了。
WebSocket协议
WebSocket协议本质上是一个基于TCP的协议。为了建立一个WebSocket连接,客户端浏览器首先要向服务器发起一个HTTP请求,这个请求和通常的HTTP请求不同,包含了一些附加头信息,其中附加头信息”Upgrade: WebSocket”表明这是一个申请协议升级的 HTTP 请求(详细的WebSocket消息的内容这里就不详细说了,基本和HTTP的差不多,而且都是由WebSocket对象自动发送和接收的,对用户透明),服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。
WebSocket API最伟大之处在于服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息。WebSocket并不限于以Ajax(或XmlHttpRequest)方式通信,因为Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以彼此相互推送信息;XmlHttpRequest通信受到域的限制,而WebSocket允许跨域通信。
需要注意的问题是,除了安全和性能以外,服务端只管往socket里面写数据就可以了,WebSocket的通信数据全部是以”\x00″开头以”\xFF”结尾的,无论是服务端发出的数据还是客户端发送的数据都遵从这个格式,唯一不同的是客户端的WebSocket对象能够自动将头尾去除,获得主体数据,这就省却了在客户端处理原始数据的必要,而且WebSocket通信的消息总是UTF-8格式的。
WebSocket 服务端编程模型
- Kaazing WebSocket Gateway: 一个 Java 实现的WebSocket Server
- mod_pywebsocket: 一个 Python 实现的WebSocket Server
- Netty:一个 Java 实现的网络框架其中包括了对WebSocket的支持
- node.js:一个 Server 端的 JavaScript 框架提供了对WebSocket的支持
- ...
如果以上的 WebSocket 服务端实现不能满足当前的业务需求的话,开发人员完全可以根据 WebSocket 规范自己实现一个服务器。也正是由于有JavaScript的版本,才使得JavaScript脱离了浏览器的限制,走向服务器端,从而再次进入人们的视线中。
服务端的编程一般是要处理以下任务:
- 运行HTTP服务器;
- 对于不同的请求,根据请求的URL,服务器给予不同的响应,也就是路由程序,用于把请求对应到请求处理程序;
- 当请求被服务器接收并通过路由传递之后,需要可以对其进行处理,因此我们需要最终的请求处理程序 。
最简单的服务端程序就是启动HTTP服务器,如下所示:
http.createServer( function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
启动服务器以后,在浏览器中输入://localhost:8888就可以显示"Hello World"了。
WebSocket客户端编程模型
WebSocket编程实际上就连接服务器并处理各种事件,下面是JavaScript的接口:
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"(也可以是"wss"), send 方法就是发送数据到服务器端,close 方法就是关闭连接。除了这些方法,还有一些很重要的事件:onopen,onmessage,onerror 以及 onclose。
下面就是一个典型的客户端编程模型,至于网站提供的功能,那就是JavaScript与html5的事了。
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);
}
WebSocket 的风险
目前对HTML5支持的比较好的主流的浏览器如下:Firefox 4、Chrome 4、Opera 10.70以及Safari 5。推荐还是安装Chrome浏览器,速度快,调试工具好。