远观
从东边看
.。。。
首先说下Comet这个词,Comet 这个词是最早由Alex Russell(Dojo Toolkit 的项目 Lead)提出的,称基于 HTTP 长连接、无须在浏览器端安装插件的"服务器推(Push)"技术为"Comet"。
1.HTTP拉取方式(pull)
在这种传统的方法中,客户端以用户可定义的时间间隔去检查服务器上的最新数据。这种拉取方式的频率要足够高才能保证很高的数据精确度,但高频率可能会导致多余的检查,从而导致较高的网络流量。而另一方面,低频率则会导致错过更新的数据。理想地,拉取的时间间隔应该等于服务器状态改变的速度。常见的实现如利用 "<meta http-equiv="refresh" content="5" />" tag,当然利用xmlHttpRequest定时取也是一种方法。
2.HTTP流(Push机制)
HTTP流有两种形式:
* Page Stream: 页面上不间断的HTTP连接响应(HTTP 1.1 Keep Alive).
通过在 HTML 页面里嵌入一个隐�帧(iframe),然后将这个隐�帧的 SRC 属性设为对一个长连接的请求,服务器端就能源源不断地往客户端输入数据。
* Service Stream: XMLHttpRequest连接中的服务器数据流。
客户端是在 XMLHttpRequest 的 readystate 为 4(即数据传输结束)时调用回调函数,进行信息处理。当 readystate 为 4 时,数据传输结束,连接已经关闭。Mozilla Firefox 提供了对 Streaming AJAX 的支持,即 readystate 为 3 时(数据仍在传输中),客户端可以读取数据,从而无须关闭连接,就能读取处理服务器端返回的信息。IE 在 readystate 为 3 时,不能读取服务器返回的数据,目前 IE 不支持基于 Streaming AJAX。
注:使用 Page Stream(iframe) 请求一个长连接有一个很明显的不足之处:IE、Morzilla Firefox 下端的进度栏都会显示加载没有完成,而且 IE 上方的图标会不停的转动,表示加载正在进行。Google 的天才们使用一个称为"htmlfile"的 ActiveX 解决了在 IE 中的加载显示问题,并将这种方法用到了 gmail+gtalk 产品中。Alex Russell 在 "What else is burried down in the depth's of Google's amazing JavaScript?"文章中介绍了这种方法。Zeitoun 网站提供的 comet-iframe.tar.gz,封装了一个基于 iframe 和 htmlfile 的 JavaScript comet 对象,支持 IE、Mozilla Firefox 浏览器,可以作为参考。(http://alex.dojotoolkit.org/?p=538)
3.长时间轮询(Long Polling)
也就是所谓的异步轮询(Asynchronous Polling),这种方式是纯服务器端推送方式和客户端拉取方式的混合。它是基于BAYEUX协议(http://svn.xantus.org/shortbus/trunk/bayeux/bayeux.html) 的。这个协议遵循基于主题的发布――订阅机制。在订阅了某个频道后,客户端和服务器间的连接会保持打开状态,并保持一段事先定义好的时间(默认为45 秒)。如果服务器端没有事件发生,而发生了超时,服务器端就会请求客户端进行异步重新连接。如果有事件发生,服务器端会发送数据到客户端,然后客户端重新连接。
1. 服务器端会阻塞请求直到有数据传递或超时才返回。
2. 客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。
3. 当客户端处理接收的数据、重新建立连接时,服务器端可能有新的数据到达;这些信息会被服务器端保存直到客户端重新建立连接,客户端会一次把当前服务器端所有的信息取回。
4.Flash XMLSocket(push机制)
这种方案实现的基础是:
1. 安装了 Flash 播放器,Flash 提供了 XMLSocket 类(Flash 7.0.14以上版本)。
2. JavaScript 和 Flash 的紧密结合:在 JavaScript 可以直接调用 Flash 程序提供的接口。
具体实现方法:在 HTML 页面中内嵌入一个使用了 XMLSocket 类的 Flash 程序。JavaScript 通过调用此 Flash 程序提供的套接口接口与服务器端的套接口进行通信。JavaScript 在收到服务器端以 XML 格式传送的信息后可以很容易地控制 HTML 页面的内容显示。
关于如何去构建 JavaScript 与 Flash XMLSocket 的 Flash 程序,以及如何在 JavaScript 里调用 Flash 提供的接口,我们可以参考 AFLAX(Asynchronous Flash and XML)项目提供的 Socket Demo 以及 SocketJS(请参见 [http://www.aflax.org/ Asynchronous Flash and XML,提供了强大的 Flash、Javascript 库和很多范例。])。
Javascript 与 Flash 的紧密结合,极大增强了客户端的处理能力。从 Flash 播放器 V7.0.19 开始,已经取消了 XMLSocket 的端口必须大于 1023 的限制。Linux 平台也支持 Flash XMLSocket 方案。但此方案的缺点在于:
1. 客户端必须安装 Flash 播放器;
2. 因为 XMLSocket 没有 HTTP 隧道功能,XMLSocket 类不能自动穿过防火墙;
3. 因为是使用Socket接口,需要设置一个通信端口,防火墙、代理服务器也可能对非 HTTP 通道端口进行限制;
4. 必须使用XML格式作为消息格式,数据冗余增大。
此方案在一些网络聊天室,网络互动游戏中得到广泛使用。
5. Java Applet(Push机制)
类似于Flash XMLSocket方式。目前已经很少使用,原因极可能是因在手机等移动终端缺少支持。
总结和建议:
如果我们想要高数据一致性和高网络性能,我们就应该选择推送方式。但是,推送会带来一些扩展性问题;服务器应用程序CPU使用率是拉取方式的7倍。根据TUD(http://swerl.tudelft.nl/twiki/pub/Main/TechnicalReports/TUD-SERG-2007-016.pdf)的测试结果,服务器性能会在350-500个用户时趋于饱和。对于更大数量的用户,服务器端需要维护大量并发的长连接。在这种应用背景下,服务器端需要考虑负载均衡和集群技术;或是在服务器端为长连接作一些改进。
使用拉取方式,要想达到完整的数据一致性以及很高的网络性能是很困难的。如果拉取的时间间隔大于数据更新的时间间隔,就会发生一些数据的遗失。而如果小于数据更新的时间间隔,网络性能就会受到影响。拉取方式只有在拉取时间间隔等同于数据更新时间间隔时,才会恰到好处。但是,为了达到那样的目标,我们就需要提前知道准确的数据更新时间间隔。然而,数据更新的时间间隔很少是静态不变并可以预知的。这使得拉取方式只有在数据是根据某种特定模式发布的情况才有用。
控制信息与数据信息使用不同的 HTTP 连接
使用长连接时,存在一个很常见的场景:客户端网页需要关闭,而服务器端还处在读取数据的堵塞状态,客户端需要及时通知服务器端关闭数据连接。服务器在收到关闭请求后首先要从读取数据的阻塞状态唤醒,然后释放为这个客户端分配的资源,再关闭连接。所以在设计上,我们需要使客户端的控制请求和数据请求使用不同的 HTTP 连接,才能使控制请求不会被阻塞。
在实现上,如果是基于 iframe 流方式的长连接,客户端页面需要使用两个 iframe,一个是控制帧,用于往服务器端发送控制请求,控制请求能很快收到响应,不会被堵塞;一个是显示帧,用于往服务器端发送长连接请求。如果是基于 AJAX 的长轮询方式,客户端可以异步地发出一个 XMLHttpRequest 请求,通知服务器端关闭数据连接。
在客户和服务器之间保持"心跳"信息
在浏览器与服务器之间维持一个长连接会为通信带来一些不确定性:因为数据传输是随机的,客户端不知道何时服务器才有数据传送。服务器端需要确保当客户端不再工作时,释放为这个客户端分配的资源,防止内存泄漏。因此需要一种机制使双方知道大家都在正常运行。在实现上:
1. 服务器端在阻塞读时会设置一个时限,超时后阻塞读调用会返回,同时发给客户端没有新数据到达的心跳信息。此时如果客户端已经关闭,服务器往通道写数据会出现异常,服务器端就会及时释放为这个客户端分配的资源。
2. 如果客户端使用的是基于 AJAX 的长轮询方式;服务器端返回数据、关闭连接后,经过某个时限没有收到客户端的再次请求,会认为客户端不能正常工作,会释放为这个客户端分配、维护的资源。
3. 当服务器处理信息出现异常情况,需要发送错误信息通知客户端,同时释放资源、关闭连接。
【附】开源项目资源
Cometd(http://cometd.com/) Comet framework sponsored by the Dojo foundation.
Orbited(http://orbited.org/) 可缩放的分布式Comet 服务器 (python 语言实现)
Pushlets(http://www.pushlets.com/)一个开源框架,可以让服务器端java对象推送事件到浏览器端javascript,java applet,或者flash应用程序
Jetty(http://jetty.mortbay.org/) Servlet server java 实现
Pushup(http://pushup.causology.net/) Comet server (C++实现)
近期,香港区全国政协委员、金融专家刘梦熊撰写《我为人民鼓与呼》一文,在香港三家媒体以整版篇幅发表,引发震撼,各界关注。刘梦熊疾言厉色质问中 国财政金融管理当局有关拍板人:"你们这班败家子哪里来这麼大的胆子,拿国家人民的钱,来买天文数字的3763亿美元美国"两房"公司债券。现在"两房" 基本上已破產,你们如何向全国人民交代?如此离谱决策有没有黑幕,人大会应立即组织特别调查组彻查,追究责任!"
犹如闹市中引爆炸弹,引起社会各界,特别是金融乃至经济界强烈反响。不过都是在高层经济圈内,大陆平面主流媒体完全回避和沉默,网站也大量删除评论帖。详细情况是这样:——
次贷危机下,美国的两家房贷抵押机构"房地美"和"房利美"公司行将崩盘破产,荣登美国"两房"公司外国债权人之榜首的居然是中国,一共持有涉及该两间公司高达3763亿美元债券,约占中国外汇储备总额21% 。国际经济界称为一件匪夷所思的大丑闻。
国家资料显示,自2004年开始,中国对美国债券的持有一直在高速增长,从2004年到2007年惊人增长三倍,高达到9220亿美元。仅2006年到去 年2007年间,中国对美国债券的持有增长66%。在美国次按危机即将露出狰狞面目的前夜,中国仍然痴心不改地不断大手笔增持美国债券。究竟是谁拥有在这 样疯狂地处置中国巨额外汇储备的权利,如痴呆一样疯狂购买美国债券?
同样是亚洲大国的印度,外汇储备也很客观,但印度对美国"两房"债券持有量才2300万美元而已,人家是意思意思,中国的3763亿竟然是印度的一万六千倍,差不多是三万亿港币。这样投进美国"两房"是完全不可思议的!
国际公认的原则是,外汇储备公认的投资原则是安全第一,分散为宜,但中国财金当局却将外储的百分之二十以上投资于美国"两房",这相当于将大部分鸡蛋放在 一个篮子。当年亚洲金融风暴,香港和东南亚楼市崩溃,还闹出「负资产」,业主和银行一齐遭殃,说明房屋按揭本身风险很大,其衍生债券更是危险品。
不能只集中在一个菜篮里,这是金融投资常识性的金科玉律。外匯储备投资原则是安全第一,稳健至上,比重分散,结构多元。可是我们那些可爱的受握重权的国家外汇管理局、财政部、中国人民银行的败家子一般的官员,个个还都是硕士、博士学位!
就冲这点,中国民众还有什么脸面去嘲笑印度!叫人家阿三,自己都快成阿大了。到底是谁祸害中国如此吃亏,不,是重创,而成为世界笑柄!
我一贯就对什么莺歌燕舞的盛大晚会、开幕式不以为然,花钱给人看的东西,值得那样好面子搞成空前绝后的拔高?看清楚自己的弱点、忧患,早早修复自己可能被对手抓住而致命的死穴比什么都重要!
我认为:这件金融丑闻的暴露,实质上对中国经济重创之巨,对国民信心和精神打击之大,简直可以抵消大批我们自己宣传的其他成就光环。这决不是一般的问题, 甚至不是什么重大失误!不能用失误的概念,而是直接叫做中了"杀招"!它的背后是应该是严重的渎职 战略间谍的性质!
中国经济学家都在干什么,受那些所谓主流经济学家提出的高论影响而实行的政策,最后使谁最终受益,使谁陷入深深窘境了呢? 那些"主张对内狂引境外战略投资者、让其大赚贱卖的银行原始股;对外大力推出中国优质大型企业或国有垄断企业境外上市,向海外慷慨派送十倍于融资的分红" 的经济专家到底在干什么,他们的底细和真实身份到底是谁?
近些年来,境外利益集团在华活动十分活跃,境外利益集团在华活动手法多端:有的熟谙中国国情,巧妙利用各方人脉,想方设法接近各级领导人,进行商业游说, 影响相关决策,为商业活动铺路;有的境外利益集团对有关部委研究机构与学者给予丰厚的课题经费等途径,让他们利用自己的所谓研究成果和影响为境外跨国企业 集团谋利、鸣锣开道,对中国相关部门决策与立法施加影响。于是中国的经济专家和经济官员们他们当中有不少靠着暴利集团贿赂、靠着境外集团资助做研究报告, 通过境内外媒体精心包装、刻意打造,提供各类活动舞台,提高知名度、美誉度,从而成为中国国内行业精英,拥有强大的话语权,为国内外的利益集团鸣锣开道呼 号、充当掮客买办,多年来实际也真正影响了行业乃至国家经济决策。
我一直认为近年国家经济领域这样的怪异诡秘的现象和行为,决不仅仅是表面专家贪财、官员渎职那么简单,应该是境外对手和敌对势力精心地策划和不懈的努力后,其战略间谍的成功之作。今天,这场惊天的美国债券丑闻,更坚定了我的判断