代码改变世界

即时Web通信总结

2014-02-24 21:57  OshynSong  阅读(2612)  评论(10编辑  收藏  举报

即时Web通信在一些对数据实时性要求特别严格的应用中十分重要,如监控系统、报价系统、股票交易系统和即时在线聊天应用等,由于http协议设计当初是为了服务器端响应客户端的请求而设计的,只能在客户端主动发送请求后进行处理然后返回结果。为了实现上述各种即时应用的功能,出现了一系列“Hack”的手段来模拟实现服务器端主动推送信息的功能,也就是模拟了服务器和客户端直接全双工的通信。这样主要考虑的是如下问题:

  • 客户端如何接收、处理信息,是否需要使用套接口或是使用远程调用。客户端呈现给用户的是 HTML 页面还是 Java applet 或 Flash 窗口。如果使用套接口和远程调用,怎么和 JavaScript 结合修改 HTML 的显示。
  • 客户与服务器端通信的信息格式,采取怎样的出错处理机制。
  • 客户端是否需要支持不同类型的浏览器如 IE、Firefox,是否需要同时支持 Windows 和 Linux 平台。

与此同时,HTML5中websocket的出现作为新一代实现真正服务器与客户端全双工连接的方式,是目前以及今后开发实时Web应用的主要实现方法。

一、基于客户端套接口的实现

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翻译为中文就是“彗星”,用在这里就是指客户端与服务器端建立连接后,会像彗星托着长长的尾巴一样一直保持连接,从而就可以实现服务器主动发送数据到客户端的即时要求。总结起来,基于comet模型的实现方式概括为以下两种:Streaming和Polling。

1、Streaming

使用基于iframe的html页面标记,通过在html页面嵌入一个隐藏帧,将其的src属性设置为对一个长连接的请求,这样服务器端就可以不断往客户端输入数据。

服务器端返回的数据不是具体在页面显示的html文档内容,而是返回对客户端javascript函数调用的javascript代码,类似于:

 

[javascript] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. <script type="text/javascript">js_func("data from server");</script>  

 

ifream收到这样的script代码后写入到页面,浏览器的javascript引擎执行这些javascript代码,就达到了服务器推送的目的。其中服务器端代码需要做特殊处理,使用一个无限循环保持这个连接,每次循环flush内容,然后sleep一段时间后进入下一次循环。

这种方式的优点是在绝大多数浏览器都支持,不足在于缺乏一种有效的错误处理机制,还有就是跟踪推送中间过程的不同状态基本是不可能的,同时必须配合非阻塞的服务器才能使用,否则多人访问同一页面将服务器IO占满之后就不能访问了。

2、Polling

自从有了Ajax以后,通过使用javascript代码调用XMLHttpRequest对象在客户端发送http请求就得以实现。与基于插件形式实现的不同的是:

  • 服务器端会阻塞请求直到有数据传递或超时才返回。
  • 客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。
  • 当客户端处理接收的数据、重新建立连接时,服务器端可能有新的数据到达;这些信息会被服务器端保存直到客户端重新建立连接,客户端会一次把当前服务器端所有的信息取回。
Polling就是一种编程模式,通过客户端javascript不断发送请求询问服务器是否有变更的数据,每次发送询问的请求之后,可以选择关闭连接,这就是一般的轮询,如果保持连接不关闭就是长轮询。这种方式,请求异步发出,无需安装插件,同时各浏览器提供都支持。
普通轮询:客户端发送利用javascript的setInteval函数每隔一段时间就想服务器发送一个Ajax请求来取回服务器的数据,这种方式服务器端代码不需做特殊处理。如每隔一分钟检查一次Cookie是否过期。
长连接:客户端代码发送一个Ajax请求后,在onreadystatechange处理函数中判断readyState为3的时候就接收服务器的数据,并记录下此时接收数据的位置,使用substring函数取得当前数据后现实到DOM中。此时服务器端代码需要做特殊处理,服务器端php脚本中使用一个无限循环,每一次循环使用flush输出结果后sleep一段时间然后进行下一次循环输出。这样就将所有负担交给了服务器端。需要一直保持这个到客户端的连接。服务器代码与基于iframe的方案相同。这种做法的缺点就是IE不能在readyState为3的时候处理返回的数据,因此不兼容IE。
长轮询:目前除了Websocket之外应用最广泛的解决方案,iframe和长连接都是一直保持连接,但长轮询则是发送一个长时间等待的请求后,当服务器又数据返回时就返回数据并断掉连接,客户端接收到数据后再次发送一个长时间连接的请求。这个方案也需要服务器端的特殊处理来配合。

三、Websocket

HTML5提供了Websocket,定义了一个全双工通信的信道,这不仅仅是对常规HTTP通信的一种增量,同时是一个巨大进步,对即时的、事件驱动的Web程序的实现提供了无线的开发空间。

使用轮询时,由于实时数据不可测,因此不能避免有不必要的请求,这样在低消息率情况下会有很多无用的连接不断打开和关闭,浪费流量

使用长轮询时,服务器收到请求后在一段时间保持打开,在时间内服务器收到通知则发送响应,否则当时间到了的时候就终止打开的请求,但是当信息量很大的时候,与轮询相比并没有实质性的性能改善

使用流解决方案时,浏览器发送请求后服务器会一直保持打开状态,且是无限期或一段时间内都处于打开状态。这样当访问量很大时,每个连接都会消耗服务器很多资源,对服务器端的压力很大。同时由于流任然是封装在http中,期间的防火墙和代理服务器可能对响应消息进行缓冲从而造成消息传递的时延

同时,只要是基于http请求的凡事都会涉及http请求头和响应头,包含有大量不必要的数据,这样大量耗费了网络带宽,而真正用于传递有效信息的数据可能只有几个字节,得不偿失。同时半双工http基础上模拟全双工需要使用两个连接,一个用于下行数据流,一个用于上行数据流。这样两个连接的协作也会造成大量的资源消耗

综合上述,websocket的出现就是为了解决上述所有解决方案的不足而设计的。websocket可以实现500:1甚至1000:1的http消息头流量的缩减,同时实现3:1的通信延迟的缩减。同时实现起来简单高效。

以上总结是对整个即时Web通信的概念性总结,个人总觉得对整体有个概念性总结后,就不会在具体实现的时候以致盲目,关于具体实现细节在见另外博文,同时各人实现起来的方式也会有所不同,愿和大家一起交流学习。