CometAjax数据自动回传技术研究.docx
《CometAjax数据自动回传技术研究.docx》由会员分享,可在线阅读,更多相关《CometAjax数据自动回传技术研究.docx(15页珍藏版)》请在冰豆网上搜索。
![CometAjax数据自动回传技术研究.docx](https://file1.bdocx.com/fileroot1/2023-4/21/21f21b37-a3f3-42f2-a1f4-5e521a0e4e42/21f21b37-a3f3-42f2-a1f4-5e521a0e4e421.gif)
CometAjax数据自动回传技术研究
Comet:
基于HTTP长连接的“服务器推”技术
很多应用都需要将后台发生的变化,实时传送到客户端,而无须客户端不停地刷新、发送请求。
本文首先介绍、比较了常用的“服务器推”方案,着重介绍了Comet-使用HTTP长连接、无须浏览器安装插件的两种“服务器推”方案:
基于AJAX的长轮询方式;基于iframe及htmlfile的流方式。
最后分析了开发Comet应用需要注意的一些问题,以及如何借助开源的Comet框架-pushlet构建自己的“服务器推”应用。
将“服务器推”应用在Web程序中,首先考虑的是如何在功能有限的浏览器端接收、处理信息:
1.客户端如何接收、处理信息,是否需要使用套接口或是使用远程调用。
客户端呈现给用户的是HTML页面还是Javaapplet或Flash窗口。
如果使用套接口和远程调用,怎么和JavaScript结合修改HTML的显示。
2.客户与服务器端通信的信息格式,采取怎样的出错处理机制。
3.客户端是否需要支持不同类型的浏览器如IE、Firefox,是否需要同时支持Windows和Linux平台。
基于客户端套接口的“服务器推”技术
FlashXMLSocket
这种方案实现的基础是:
1.Flash提供了XMLSocket类。
2.JavaScript和Flash的紧密结合:
在JavaScript可以直接调用Flash程序提供的接口。
具体实现方法:
在HTML页面中内嵌入一个使用了XMLSocket类的Flash程序。
JavaScript通过调用此Flash程序提供的套接口接口与服务器端的套接口进行通信。
JavaScript在收到服务器端以XML格式传送的信息后可以很容易地控制HTML页面的内容显示。
Javascript与Flash的紧密结合,极大增强了客户端的处理能力。
从Flash播放器V7.0.19开始,已经取消了XMLSocket的端口必须大于1023的限制。
Linux平台也支持FlashXMLSocket方案。
但此方案的缺点在于:
1.客户端必须安装Flash播放器;
2.因为XMLSocket没有HTTP隧道功能,XMLSocket类不能自动穿过防火墙;
3.因为是使用套接口,需要设置一个通信端口,防火墙、代理服务器也可能对非HTTP通道端口进行限制;
不过这种方案在一些网络聊天室,网络互动游戏中已得到广泛使用。
JavaApplet套接口
在客户端使用JavaApplet,通过.Socket或.DatagramSocket或.MulticastSocket建立与服务器端的套接口连接,从而实现“服务器推”。
这种方案最大的不足在于Javaapplet在收到服务器端返回的信息后,无法通过JavaScript去更新HTML页面的内容。
基于HTTP长连接的“服务器推”技术
Comet简介
下面将介绍两种Comet应用的实现模型。
基于AJAX的长轮询(long-polling)方式
AJAX的出现使得JavaScript可以调用XMLHttpRequest对象发出HTTP请求,JavaScript响应处理函数根据服务器返回的信息对HTML页面的显示进行更新。
使用AJAX实现“服务器推”与传统的AJAX应用不同之处在于:
1.服务器端会阻塞请求直到有数据传递或超时才返回。
2.客户端JavaScript响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。
3.当客户端处理接收的数据、重新建立连接时,服务器端可能有新的数据到达;这些信息会被服务器端保存直到客户端重新建立连接,客户端会一次把当前服务器端所有的信息取回。
因为这种方案基于AJAX,具有以下一些优点:
请求异步发出;无须安装插件;IE、MozillaFireFox都支持AJAX。
MozillaFirefox提供了对StreamingAJAX的支持,即readystate为3时(数据仍在传输中),客户端可以读取数据,从而无须关闭连接,就能读取处理服务器端返回的信息。
IE在readystate为3时,不能读取服务器返回的数据,目前IE不支持基于StreamingAJAX。
基于Iframe及htmlfile的流(streaming)方式
通过在HTML页面里嵌入一个隐蔵帧,然后将这个隐蔵帧的SRC属性设为对一个长连接的请求,服务器端就能源源不断地往客户端输入数据。
每次数据传送不会关闭连接,连接只会在通信出现错误时,或是连接重建时关闭(一些防火墙常被设置为丢弃过长的连接,服务器端可以设置一个超时时间,超时后通知客户端重新建立连接,并关闭原来的连接)。
用iframe请求一个长连接有一个很明显的不足之处:
IE、MorzillaFirefox下端的进度栏都会显示加载没有完成,而且IE上方的图标会不停的转动,表示加载正在进行。
Google的天才们使用一个称为“htmlfile”的ActiveX解决了在IE中的加载显示问题,并将这种方法用到了gmail+gtalk产品中。
使用Comet模型开发自己的应用
上面介绍了两种基于HTTP长连接的“服务器推”架构,更多描述了客户端处理长连接的技术。
对于一个实际的应用而言,系统的稳定性和性能是非常重要的。
将HTTP长连接用于实际应用,很多细节需要考虑。
不要在同一客户端同时使用超过两个的HTTP长连接
HTTP1.1规范中规定,客户端不应该与服务器端建立超过两个的HTTP连接,新的连接会被阻塞。
服务器端的性能和可扩展性
但是AJAX的应用使请求的出现变得频繁,而Comet则会长时间占用一个连接,上述的服务器模型会变得非常低效,甚至可能会阻塞新的连接。
控制信息与数据信息使用不同的HTTP连接
使用长连接时,存在一个很常见的场景:
客户端网页需要关闭,而服务器端还处在读取数据的堵塞状态,客户端需要及时通知服务器端关闭数据连接。
服务器在收到关闭请求后首先要从读取数据的阻塞状态唤醒,然后释放为这个客户端分配的资源,再关闭连接。
所以在设计上,我们需要使客户端的控制请求和数据请求使用不同的HTTP连接,才能使控制请求不会被阻塞。
在客户和服务器之间保持“心跳”信息
在浏览器与服务器之间维持一个长连接会为通信带来一些不确定性:
因为数据传输是随机的,客户端不知道何时服务器才有数据传送。
服务器端需要确保当客户端不再工作时,释放为这个客户端分配的资源,防止内存泄漏。
因此需要一种机制使双方知道大家都在正常运行。
在实现上:
1.服务器端在阻塞读时会设置一个时限,超时后调用会返回,同时发给客户端没有新数据到达的心跳信息。
2.经过某个时限没有收到客户端的再次请求,会认为客户端不能正常工作,会释放资源。
3.当服务器出现异常,需要通知客户端,同时释放资源。
Pushlet-开源Comet框架
Pushlet是一个开源的Comet框架,在设计上有很多值得借鉴的地方,对于开发轻量级的Comet应用很有参考价值。
观察者模型
Pushlet使用了观察者模型:
客户端发送请求,订阅感兴趣的事件;服务器端为每个客户端分配一个会话ID作为标记,事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。
客户端JavaScript库
pushlet提供了基于AJAX的JavaScript库文件用于实现长轮询方式的“服务器推”;还提供了基于iframe的JavaScript库文件用于实现流方式的“服务器推”。
posted@2008-06-2020:
58winnerlan阅读
(2)评论(0) 编辑收藏所属分类:
Web实时技术
类似于QQ游戏百万人同时在线的服务器架构实现
2008年6月20日今天,2小时之前|winnerlan
类似于QQ游戏百万人同时在线的服务器架构实现
QQ游戏于前几日终于突破了百万人同时在线的关口,向着更为远大的目标迈进,这让其它众多传统的棋牌休闲游戏平台黯然失色,相比之下,联众似乎已经根本不是QQ的对手,因为QQ除了这100万的游戏在线人数外,它还拥有3亿多的注册量(当然很多是重复注册的)以及QQ聊天软件900万的同时在线率,我们已经可以预见未来由QQ构建起来的强大棋牌休闲游戏帝国。
那么,在技术上,QQ游戏到底是如何实现百万人同时在线并保持游戏高效率的呢?
事实上,针对于任何单一的网络服务器程序,其可承受的同时连接数目是有理论峰值的,通过C++中对TSocket的定义类型:
word,我们可以判定这个连接理论峰值是65535,也就是说,你的单个服务器程序,最多可以承受6万多的用户同时连接。
但是,在实际应用中,能达到一万人的同时连接并能保证正常的数据交换已经是很不容易了,通常这个值都在2000到5000之间,据说QQ的单台服务器同时连接数目也就是在这个值这间。
如果要实现2000到5000用户的单服务器同时在线,是不难的。
在windows下,比较成熟的技术是采用IOCP--完成端口。
与完成端口相关的资料在网上和CSDN论坛里有很多,感兴趣的朋友可以自己搜索一下。
只要运用得当,一个完成端口服务器是完全可以达到2K到5K的同时在线量的。
但,5K这样的数值离百万这样的数值实在相差太大了,所以,百万人的同时在线是单台服务器肯定无法实现的。
要实现百万人同时在线,首先要实现一个比较完善的完成端口服务器模型,这个模型要求至少可以承载2K到5K的同时在线率(当然,如果你MONEY多,你也可以只开发出最多允许100人在线的服务器)。
在构建好了基本的完成端口服务器之后,就是有关服务器组的架构设计了。
之所以说这是一个服务器组,是因为它绝不仅仅只是一台服务器,也绝不仅仅是只有一种类型的服务器。
简单地说,实现百万人同时在线的服务器模型应该是:
登陆服务器+大厅服务器+房间服务器。
当然,也可以是其它的模型,但其基本的思想是一样的。
下面,我将逐一介绍这三类服务器的各自作用。
登陆服务器:
一般情况下,我们会向玩家开放若干个公开的登陆服务器,就如QQ登陆时让你选择的从哪个QQ游戏服务器登陆一样,QQ登陆时让玩家选择的六个服务器入口实际上就是登陆服务器。
登陆服务器主要完成负载平衡的作用。
详细点说就是,在登陆服务器的背后,有N个大厅服务器,登陆服务器只是用于为当前的客户端连接选择其下一步应该连接到哪个大厅服务器,当登陆服务器为当前的客户端连接选择了一个合适的大厅服务器后,客户端开始根据登陆服务器提供的信息连接到相应的大厅上去,同时客户端断开与登陆服务器的连接,为其他玩家客户端连接登陆服务器腾出套接字资源。
在设计登陆服务器时,至少应该有以下功能:
N个大厅服务器的每一个大厅服务器都要与所有的登陆服务器保持连接,并实时地把本大厅服务器当前的同时在线人数通知给各个登陆服务器,这其中包括:
用户进入时的同时在线人数增加信息以及用户退出时的同时在线人数减少信息。
这里的各个大厅服务器同时在线人数信息就是登陆服务器为客户端选择某个大厅让其登陆的依据。
举例来说,玩家A通过登陆服务器1连接到登陆服务器,登陆服务器开始为当前玩家在众多的大厅服务器中根据哪一个大厅服务器人数比较少来选择一个大厅,同时把这个大厅的连接IP和端口发给客户端,客户端收到这个IP和端口信息后,根据这个信息连接到此大厅,同时,客户端断开与登陆服务器之间的连接,这便是用户登陆过程中,在登陆服务器这一块的处理流程。
大厅服务器:
大厅服务器,是普通玩家看不到的服务器,它的连接IP和端口信息是登陆服务器通知给客户端的。
也就是说,在QQ游戏的本地文件中,具体的大厅服务器连接IP和端口信息是没有保存的。
大厅服务器的主要作用是向玩家发送游戏房间列表信息,这些信息包括:
每个游戏房间的类型,名称,在线人数,连接地址以及其它如游戏帮助文件URL的信息。
从界面上看的话,大厅服务器就是我们输入用户名和密码并校验通过后进入的游戏房间列表界面。
大厅服务器,主要有以下功能:
一是向当前玩家广播各个游戏房间在线人数信息;二是提供游戏的版本以及下载地址信息;三是提供各个游戏房间服务器的连接IP和端口信息;四是提供游戏帮助的URL信息;五是提供其它游戏辅助功能。
但在这众多的功能中,有一点是最为核心的,即:
为玩家提供进入具体的游戏房间的通道,让玩家顺利进入其欲进入的游戏房间。
玩家根据各个游戏房间在线人数,判定自己进入哪一个房间,然后双击服务器列表中的某个游戏房间后玩家开始进入游戏房间服务器。
游戏房间服务器:
游戏房间服务器,具体地说就是如“斗地主1”,“斗地主2”这样的游戏房间。
游戏房间服务器才是具体的负责执行游戏相关逻辑的服务器。
这样的游戏逻辑分为两大类:
一类是通用的游戏房间逻辑,如:
进入房间,离开房间,进入桌子,离开桌子以及在房间内说话等;第二类是游戏桌子逻辑,这个就是各种不同类型游戏的主要区别之处了,比如斗地主中的叫地主或不叫地主的逻辑等,当然,游戏桌子逻辑里也包括有通用的各个游戏里都存在的游戏逻辑,比如在桌子内说话等。
总之,游戏房间服务器才是真正负责执行游戏具体逻辑的服务器。
这里提到的三类服务器,我均采用的是完成端口模型,每个服务器最多连接数目是5000人,但是,我在游戏房间服务器上作了逻辑层的限定,最多只允许300人同时在线。
其他两个服务器仍然允许最多5000人的同时在线。
如果按照这样的结构来设计,那么要实现百万人的同时在线就应该是这样:
首先是大厅,1000000/5000=200。
也就是说,至少要200台大厅服务器,但通常情况下,考虑到实际使用时服务器的处理能力和负载情况,应该至少准备250台左右的大厅服务器程序。
另外,具体的各种类型的游戏房间服务器需要多少,就要根据当前玩各种类型游戏的玩家数目分别计算了,比如斗地主最多是十万人同时在线,每台服务器最多允许300人同时在线,那么需要的斗地主服务器数目就应该不少于:
100000/300=333,准备得充分一点,就要准备350台斗地主服务器。
除正常的玩家连接外,还要考虑到:
对于登陆服务器,会有250台大厅服务器连接到每个登陆服务器上,这是始终都要保持的连接;
而对于大厅服务器而言,如果仅仅有斗地主这一类的服务器,就要有350多个连接与各个大厅服务器始终保持着。
所以从这一点看,我的结构在某些方面还存在着需要改进的地方,但核心思想是:
尽快地提供用户登陆的速度,尽可能方便地让玩家进入游戏中。
winnerlan2008-06-2020:
57发表评论
新闻频道
注释(0)
基于WEB的实时事件通知方案
2008年6月20日今天,2小时之前|winnerlan
基于WEB的实时事件通知方式大致有五种方案:
HTTP拉取方式(pull),HTTP流,LongPolling,FlashXMLSocket方式,JavaApplet。
首先说下Comet这个词,Comet这个词是最早由AlexRussell(DojoToolkit的项目Lead)提出的,称基于HTTP长连接、无须在浏览器端安装插件的“服务器推(Push)”技术为“Comet”。
1.HTTP拉取方式(pull)
在这种传统的方法中,客户端以用户可定义的时间间隔去检查服务器上的最新数据。
这种拉取方式的频率要足够高才能保证很高的数据精确度,但高频率可能会导致多余的检查,从而导致较高的网络流量。
而另一方面,低频率则会导致错过更新的数据。
理想地,拉取的时间间隔应该等于服务器状态改变的速度。
常见的实现如利用""tag,当然利用xmlHttpRequest定时取也是一种方法。
2.HTTP流(Push机制)
HTTP流有两种形式:
*PageStream:
页面上不间断的HTTP连接响应(HTTP1.1KeepAlive).
通过在HTML页面里嵌入一个隐蔵帧(iframe),然后将这个隐蔵帧的SRC属性设为对一个长连接的请求,服务器端就能源源不断地往客户端输入数据。
*ServiceStream:
XMLHttpRequest连接中的服务器数据流。
客户端是在XMLHttpRequest的readystate为4(即数据传输结束)时调用回调函数,进行信息处理。
当readystate为4时,数据传输结束,连接已经关闭。
MozillaFirefox提供了对StreamingAJAX的支持,即readystate为3时(数据仍在传输中),客户端可以读取数据,从而无须关闭连接,就能读取处理服务器端返回的信息。
IE在readystate为3时,不能读取服务器返回的数据,目前IE不支持基于StreamingAJAX。
注:
使用PageStream(iframe)请求一个长连接有一个很明显的不足之处:
IE、MorzillaFirefox下端的进度栏都会显示加载没有完成,而且IE上方的图标会不停的转动,表示加载正在进行。
Google的天才们使用一个称为“htmlfile”的ActiveX解决了在IE中的加载显示问题,并将这种方法用到了gmail+gtalk产品中。
AlexRussell在“Whatelseisburrieddowninthedepth'sofGoogle'samazingJavaScript?
”文章中介绍了这种方法。
Zeitoun网站提供的comet-iframe.tar.gz,封装了一个基于iframe和htmlfile的JavaScriptcomet对象,支持IE、MozillaFirefox浏览器,可以作为参考。
(http:
//alex.dojotoolkit.org/?
p=538)
3.长时间轮询(LongPolling)
也就是所谓的异步轮询(AsynchronousPolling),这种方式是纯服务器端推送方式和客户端拉取方式的混合。
它是基于BAYEUX协议(http:
//svn.xantus.org/shortbus/trunk/bayeux/bayeux.html)的。
这个协议遵循基于主题的发布——订阅机制。
在订阅了某个频道后,客户端和服务器间的连接会保持打开状态,并保持一段事先定义好的时间(默认为45秒)。
如果服务器端没有事件发生,而发生了超时,服务器端就会请求客户端进行异步重新连接。
如果有事件发生,服务器端会发送数据到客户端,然后客户端重新连接。
1. 服务器端会阻塞请求直到有数据传递或超时才返回。
2.客户端JavaScript响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。
3.当客户端处理接收的数据、重新建立连接时,服务器端可能有新的数据到达;这些信息会被服务器端保存直到客户端重新建立连接,客户端会一次把当前服务器端所有的信息取回。
4.FlashXMLSocket(push机制)
这种方案实现的基础是:
1.安装了Flash播放器,Flash提供了XMLSocket类(Flash7.0.14以上版本)。
2.JavaScript和Flash的紧密结合:
在JavaScript可以直接调用Flash程序提供的接口。
具体实现方法:
在HTML页面中内嵌入一个使用了XMLSocket类的Flash程序。
JavaScript通过调用此Flash程序提供的套接口接口与服务器端的套接口进行通信。
JavaScript在收到服务器端以XML格式传送的信息后可以很容易地控制HTML页面的内容显示。
关于如何去构建JavaScript与FlashXMLSocket的Flash程序,以及如何在JavaScript里调用Flash提供的接口,我们可以参考AFLAX(AsynchronousFlashandXML)项目提供的SocketDemo以及SocketJS(请参见[http:
//www.aflax.org/AsynchronousFlashandXML,提供了强大的Flash、Javascript库和很多范例。
])。
Javascript与Flash的紧密结合,极大增强了客户端的处理能力。
从Flash播放器V7.0.19开始,已经取消了XMLSocket的端口必须大于1023的限制。
Linux平台也支持FlashXMLSocket方案。
但此方案的缺点在于:
1.客户端必须安装Flash播放器;
2.因为XMLSocket没有HTTP隧道功能,XMLSocket类不能自动穿过防火墙;
3.因为是使用Socket接口,需要设置一个通信端口,防火墙、代理服务器也可能对非HTTP通道端口进行限制;
4.必须使用XML格式作为消息格式,数据冗余增大。
此方案在一些网络聊天室,网络互动游戏中得到广泛使用。
5.JavaApplet(Push机制)
类似于FlashXMLSocket方式。
目前已经很少使用,原因极可能是因在手机等移动终端缺少支持。
总结和建议:
如果我们想要高数据一致性和高网络性能,我们就应该选择推送方式。
但是,推送会带来一些扩展性问题;服务器应用程序CPU使用率是拉取方式的7倍。
根据TUD(http:
//swerl.tudelft.nl/twiki/pub/Main/TechnicalReports/TUD-SERG-2007-016.pdf)的测试结果,服务器性能会在350-500个用户时趋于饱和。
对于更大数量的用户,服务器端需要维护大量并发的长连接。
在这种应用背景下,服务器端需要考虑负载均衡和集群技术;或是在服务器端为长连接作一些改进。
使用拉取方式,要想达到完整的数据一致性以及很高的网络性能是很困难的。
如果拉取的时间间隔大于数据更新的时间间隔,就会发生一些数据的遗失。
而如果小于数据更新的时间间隔,网络性能就会受到影响。
拉取方式只有在拉取时间间隔等同于数据更新时间间隔时,才会恰到好处。
但是,为了达到那样的目标,我们就需要提前知道准确的数据更新时间间隔。
然而,数据更新的时间间隔很少是静态不变并可以预知的。
这使得拉取方式只有在数据是根据某种特定模式发布的情况才有用。
控制信息与数据信息使用不同的HTTP连接
使用长连接时,存在一个很常见的场景:
客户端网页需要关闭,而服务器端还处在读取数据的堵塞状态,客户端需要及时通知服务器端关闭数据连接。
服务器在收到关闭请求后首先要从读取数据的阻塞状态唤醒,然后释放为这个客户端分配的资源,再关闭连接。
所以在设计上,我们需要使客户端的控制请求和数据请求使用不同的HTTP连接,才能使控制请求不会被阻塞。