如果你一直致力于实时网络应用,在过去几年你可能了解过一些不同的改善server端和client端数据交互延迟的技术.如果你正在开发一款多人游戏,一个及时聊天系统 或者一个想twitter一样需要频繁的与服务短交互的应用,你可能想’反转’传统的交互模型.所以,与其向服务端发送请求不如让服务端发送数据给你.
如今,当我们开发类似实时的系统是,我们总会想到长连接,comet当然还有websocket.但是,他们各有各的局限性,比如,服务器实现不同,限制太多,浏览器支持不够…
下面是我的Socket.IO的一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
var
socket =
new
io.Socket();
socket.on(
'connect'
,
function
(){
// connected!
});
socket.on(
'message'
,
function
(msg){
// message coming
});
socket.send(
'Hello world!'
);
|
如果你比较熟悉WebSocket(不熟悉去看api),其主要目的是简化HTTP的双向协议.你会发现它们非常类似.但是不同的是(由于目前浏览器尚未完全实现html5)Socket.IO支持 IE6-9, Firefox 3-4, Safari 3-5, Chrome 3-6, iOS (iPhone ,iPad)和其他兼容浏览器.
在这个年代,一大部分web开发人员都在使用AJAX来实现实时交互(异步交互),就像Socket.IO一样.一些第三方js库比如jQuery,封装了兼容性较好的ajax对象来达到异步请求的功能.
比如说,如果你现在打算实时地向服务器请求资源,你可能会这样做:
1
2
3
4
5
6
7
8
9
|
setInterval(
function
(){
$.ajax({ url:
'/my/page'
, success:
function
(data){
// do something with the data
} });
}, 5000);
|
这样,每五秒钟从服务器获取数据.在我看来,这几乎是和rfc1149(ip数据报)的规范一样高效.
你可能也会减少等待的时间:
1
2
3
4
5
6
7
8
9
|
setInterval(
function
(){
$.ajax({ url:
'/my/page'
, success:
function
(data){
// do something with the data
} });
}, 100);
|
然而,你可能忽略了下面两个要点:
传统轮询的方法是不间断的向服务器请求数据,要克服它的缺点就要在服务器没有数据时保持长连接.这样也戏剧性的减少了网络延迟(长连接),所以,这也算一种服务器推送的技术.
1
2
3
4
5
6
7
8
9
|
function
load(){
$.ajax({ url:
'/my/page'
, success:
function
(){
// do something with the data
}, complete: load, timeout: 20000 });
}
|
如果你来自一个更传统的软件开发行业(比如桌面软件),你可能会想,我们为什么不保持长连接呢.
在浏览器上要实现可能有两种方法:
multipart/x-mixed-replace
MIME 类型 (即在xhr请求中设置multipart为true的XMLHTTP实例);虽然早在1995年Netsacpe就推出了这项技术(但不是对所有浏览器都有效),唯一在firefox浏览器下被普遍支持.
<iframe>时在
头部meta信息设置Transfer-encoding: chunked
andConnection: keep-alive
.这样可以在创建<script>标签,动态执行脚本,iframe内部刷新而保持父窗口不刷新,这样也可以被看作是一种服务器推送的方法.
但这样做有一个缺点,就是浏览器下方出现无休止的进度条,严重的损害了用户体验.在ie环境下,可以把 <iframe>
放到一个隐藏的文档对象中(用ActiveX对象创建的htmlfile对象).在gmail 里面的gtalk实现给就是用的这个技术.是由Alex Russell 分析/发现的.
现在,很明显地看到这些技术在一定的环境下发挥了作用.但是最根本的是现在的服务器有着不同的请求的方法:
所有这些所做的都是尽可能减少数据的延迟,但是通常我们只把XMLHTTPRequest作为一个想服务端传输数据的良好解决方案.
有了WebSocket,”一个致力于解决bs架构的双端交互并且不依靠’multiple HTTP连接’ “,像它的作者Hickson说的那样.
WebSocket 利用了HTTP/1.1规范的优势,可以说这是一个全新的协议:(有兴趣看rfc)
1
2
3
4
|
The Upgrade general-header allows the client to specify what additional communication protocols it supports and would like to use if the server finds it appropriate to switch protocols.
Examples: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
|
WebSocket在收发消息的时候并不关闭连接.除了本身的安全模型(基于utf-8编码的框架)以外,它可以完全被称作”web版的TCP”.
但是WebSocket仍存在一些问题:
Node.js 给开发人员带来了一个独特且令人兴奋的特性:你可以用当下最流行的脚本技术来编写你的无阻塞web服务器.
就像这样:
1
2
3
4
5
6
7
8
9
10
11
|
http.createServer(
function
(request, response) {
setTimeout(
function
(){
response.writeHead(200, {
'Content-Type'
:
'text/plain'
});
response.end(
'Hello Worldn'
);
}, 20000);
}).listen(8124);
|
虽然有了这个简单的api,但是你很难继续加强你的程序的逻辑.但是Socket.IO-node可以提供一个辅助的实现.下面是一个聊天程序差不多10行,同时支持服务器广播:
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
|
var
buffer = [];
io.on(
'connection'
,
function
(client){
client.send({ buffer: buffer });
client.broadcast({ announcement: client.sessionId +
' connected'
});
client.on(
'message'
,
function
(message){
var
msg = { message: [client.sessionId, message] };
buffer.push(msg);
if
(buffer.length > 15) buffer.shift();
client.broadcast(msg);
});
client.on(
'disconnect'
,
function
(){
client.broadcast({ announcement: client.sessionId +
' disconnected'
});
});
});
|
最好的是,在浏览里,它会处理你的长连接,flash socket,iframe请求.很棒把.
如果你想进一步研究Socket.IO,你可以在git repositories检出源码进一步研究,也可以看一下几个项目(注:node.js是基于v8js引擎实现的高性能web服务器,很爽有时间去看吧):