即时Web通信在一些对数据实时性要求特别严格的应用中十分重要,如监控系统、报价系统、股票交易系统和即时在线聊天应用等,由于http协议设计当初是为了服务器端响应客户端的请求而设计的,只能在客户端主动发送请求后进行处理然后返回结果。为了实现上述各种即时应用的功能,出现了一系列“Hack”的手段来模拟实现服务器端主动推送信息的功能,也就是模拟了服务器和客户端直接全双工的通信。这样主要考虑的是如下问题:
- 客户端如何接收、处理信息,是否需要使用套接口或是使用远程调用。客户端呈现给用户的是 HTML 页面还是 Java applet 或 Flash 窗口。如果使用套接口和远程调用,怎么和 JavaScript 结合修改 HTML 的显示。
- 客户与服务器端通信的信息格式,采取怎样的出错处理机制。
- 客户端是否需要支持不同类型的浏览器如 IE、Firefox,是否需要同时支持 Windows 和 Linux 平台。
一、基于客户端套接口的实现
1、Java Applet
客户端浏览器安装java插件后,通过将java applet嵌入到html页面中,通过java.net.Socekt或者java.net.DatagramSocekt或者java.net.MulticastSocket建立与服务器端的套接字接口连接,这是建立的原始的TCP套接字来实现服务器主动推送消息。其不足指出是客户端收到服务器端返回的信息后无法通过javascript更新html页面的内容。这种方法是1996年最早在Netscape2.0浏览器中实现的。
2、Flash XML Socket
客户端浏览器安装Flash插件后,利用Flash提供的XMLSocket类来建立socket连接。同时javascript与Flash联系紧密,在javascript中可以直接调用Flash程序提供的接口。
具体方法是在页面嵌入使用XMLSocket类的Flash程序,javascript通过调用Flash提供的套接口接口与服务器端套接口通信,javascript收到以XML格式返回的信息后可以很容易控制和修改hml页面的内容,因此这种方式在目前的很多应用中依然广泛使用。但是使用套接口需要设置通信端口,可能受到防火墙或者代理服务器的端口限制,同时必须要安装Flash插件才能使用。
二、Comet模型
Comet是一种实现Web推送的编程模型,能使服务器主动将变化的数据发送到客户端而无需客户端发送请求。在2001年最早使用了建立两个http socket连接的方式来实现,是基于J2SE的一个web服务器。在2006年Alex Russell在其个人博客中发表了comet这个概念,此时使用Ajax方式来实现。总结起来,基于comet模型的实现方式概括为以下两种:Streaming和Polling。
1、Streaming
使用基于iframe的html页面标记,通过在html页面嵌入一个隐藏帧,将其的src属性设置为对一个长连接的请求,这样服务器端就可以不断往客户端输入数据。
服务器端返回的数据不是具体在页面显示的html文档内容,而是返回对客户端javascript函数调用的javascript代码,类似于:
<script type="text/javascript">js_func("data from server");</script>
ifream收到这样的script代码后写入到页面,浏览器的javascript引擎执行这些javascript代码,就达到了服务器推送的目的。
这种方式的优点是在绝大多数浏览器都支持,不足在于缺乏一种有效的错误处理机制,还有就是跟踪推送中间过程的不同状态基本是不可能的。
2、Polling
自从有了Ajax以后,通过使用javascript代码调用XMLHttpRequest对象在客户端发送http请求就得以实现。与基于插件形式实现的不同的是:
- 服务器端会阻塞请求直到有数据传递或超时才返回。
- 客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。
- 当客户端处理接收的数据、重新建立连接时,服务器端可能有新的数据到达;这些信息会被服务器端保存直到客户端重新建立连接,客户端会一次把当前服务器端所有的信息取回。
三、Websocket
HTML5提供了Websocket,定义了一个全双工通信的信道,这不仅仅是对常规HTTP通信的一种增量,同时是一个巨大进步,对即时的、事件驱动的Web程序的实现提供了无线的开发空间。
使用轮询时,由于实时数据不可测,因此不能避免有不必要的请求,这样在低消息率情况下会有很多无用的连接不断打开和关闭,浪费流量。
使用长轮询时,服务器收到请求后在一段时间保持打开,在时间内服务器收到通知则发送响应,否则当时间到了的时候就终止打开的请求,但是当信息量很大的时候,与轮询相比并没有实质性的性能改善。
使用流解决方案时,浏览器发送请求后服务器会一直保持打开状态,且是无限期或一段时间内都处于打开状态。这样当访问量很大时,每个连接都会消耗服务器很多资源,对服务器端的压力很大。同时由于流任然是封装在http中,期间的防火墙和代理服务器可能对响应消息进行缓冲从而造成消息传递的时延。
同时,只要是基于http请求的凡事都会涉及http请求头和响应头,包含有大量不必要的数据,这样大量耗费了网络带宽,而真正用于传递有效信息的数据可能只有几个字节,得不偿失。同时半双工http基础上模拟全双工需要使用两个连接,一个用于下行数据流,一个用于上行数据流。这样两个连接的协作也会造成大量的资源消耗。
综合上述,websocket的出现就是为了解决上述所有解决方案的不足而设计的。websocket可以实现500:1甚至1000:1的http消息头流量的缩减,同时实现3:1的通信延迟的缩减。同时实现起来简单高效。
以上总结是对整个即时Web通信的概念性总结,个人总觉得对整体有个概念性总结后,就不会在具体实现的时候以致盲目,关于具体实现细节在见另外博文,同时各人实现起来的方式也会有所不同,愿和大家一起交流学习。