原文链接:http://www.cnblogs.com/deepleo/p/Comet.html

一、背景介绍

传统web请求,是显式的向服务器发送http Request,拿到Response后显示在浏览器页面上。这种被动的交互方式不能满足对信息实时性要求高的应用,譬如聊天室、股票交易行情、在线游戏等。Ajax轮询虽然可以解决这个问题,但是会带来增加服务器负担、带宽浪费,并且这种实现方式不够优雅。而Comet技术就是为此而生的。

本文只探讨基于浏览器的web端服务器推技术。服务器推技术在现实应用中有一些解决方案,主要分两类:一类是需要浏览器额外安装插件,基于套接口传送信息或者是基于RMI、CORBA进行远程调用,另一类则无需浏览器安装任何插件,就是本文着重讲的HTTP长连接技术:Coment。Alex Russell(Dojo Toolkit 的项目 Lead)称这种基于 HTTP 长连接、无须在浏览器端安装插件的“服务器推”技术为“Comet”。

写本文的目的:网上的资料比较零碎,博客园的文章基本都是代码+代码,或者直接翻译别人的成果,而对于原理性的东西讲的很少。本文就是给有兴趣或者即将开发服务器推技术的程序员一个技术概览,摸清行内来龙去脉。我比较忌讳对一种新技术,上来就Focus到某个具体的技术上而不能自拔,盲人摸象。我们在定系统框架,敲定技术解决方案之前应该比较各个实现方案技术的优缺点,这样才能做出好的系统来。

二、Comet实现模型

1.HTTP Long Polling:基于 AJAX 的长轮询方式     众所周知,AJAX可以异步调用XMLHttpRequest对象发送HttpRequest,Javascript响应处理函数根据服务端返回的信息对HTML页面显示进行更新。而使用AJAX实现服务器推与传统AJAX应用的不同之处在于:

a.服务器端会阻塞请求直到有数据返回或者超时;

b.客户端JS响应函数在处理完服务端返回的信息后会再次发出请求,重新建立连接;

如图1所示,因为这种方案基于 AJAX,具有以下一些优点:请求异步发出;无须安装插件;IE、Mozilla FireFox 都支持 AJAX。

图1:基于 AJAX 的长轮询方式

2.HTTP Streaming:基于 Iframe 及 htmlfile 的流方式     通过在 HTML 页面里嵌入一个隐蔵帧,然后将这个隐蔵帧的 SRC 属性设为对一个长连接的请求,服务器端就能源源不断地往客户端输入数据。如图2所示。
图2. 基于流方式的服务器推模型

两种方案对比:

a.在对返回的数据处理方面:方案2(IFrame)返回的是对客户端javascript调用,,如“<script type="text/javascript">js_func(“data from server ”)</script>”。服务器端将返回的数据作为客户端 JavaScript 函数的参数传递;客户端浏览器的 Javascript 引擎在收到服务器返回的 JavaScript 调用时就会去执行代码。而方案1(AJAX)返回的是数据,通过JS可以很方便的操作DOM。

b.使用IFrame还有一个明显不足:IE、Morzilla Firefox 下端的进度栏都会显示加载没有完成,而且 IE 上方的图标会不停的转动,表示加载正在进行。不过这个问题已经被Google技术人员解决,并应用到Gtalk中,解决方案是:ActiveX 控件解决 iframe 请求长连接时 IE 的加载显示问题,原文地址:“What else is burried down in the depth’s of Google’s amazing JavaScript?

三、实际开发时应该注意的问题

对于一个实际的应用而言,系统的稳定性和性能是非常重要的。将 HTTP 长连接用于实际应用,很多细节需要考虑。

1.不要在同一客户端同时使用超过两个的 HTTP 长连接

这个是由于HTTP 1.1 规范中规定:客户端不应该与服务器端建立超过两个的 HTTP 连接,新的连接会被阻塞。所以,在设计上考虑让多个 frame(AJAX)共用一个长连接。

2.服务器端的性能和可扩展性     一般的WEB服务器是为每个连接创建一个线程,所以在使用Comet时,服务器要维护大量并发,长期存在的长连接。在这种背景下,就需要服务器负载均衡和集群技术,或者在服务端做一些优化。这篇文章:http://rdc.taobao.com/blog/cs/?p=1062的测试表明:200万个Http长连接占用率19G服务器内存,一个大约9kb;所以,你可以算一下你的服务器最多可以维护多少个长连接。

3.控制信息与数据信息使用不同的 HTTP 连接

用长连接时,存在一个很常见的场景:客户端网页需要关闭,而服务器端还处在读取数据的堵塞状态,客户端需要及时通知服务器端关闭数据连接。服务器在收到关闭请求后首先要从读取数据的阻塞状态唤醒,然后释放为这个客户端分配的资源,再关闭连接。

所以在设计上,我们需要使客户端的控制请求和数据请求使用不同的 HTTP 连接,才能使控制请求不会被阻塞。

在实现上,如果是基于 iframe 流方式的长连接,客户端页面需要使用两个 iframe,一个是控制帧,用于往服务器端发送控制请求,控制请求能很快收到响应,不会被堵塞;一个是显示帧,用于往服务器端发送长连接请求。如果是基于 AJAX 的长轮询方式,客户端可以异步地发出一个 XMLHttpRequest 请求,通知服务器端关闭数据连接。

4.在客户和服务器之间保持“心跳”信息

客户端不知道何时服务器才有数据传送。服务器端需要确保当客户端不在状态(工作)时,释放为这个客户端分配的资源,防止内存泄漏。因此需要一种机制使双方知道大家都在正常运行。

四、Comet框架介绍     由于Comet早在2006.2月就提出来了,所以并不是什么新鲜玩意,框架还是很多的,譬如:Dojox.cometd, Pushlet,SingalR。

Dojox.cometd:Comet概念的的提出者Alex Russel主导的Dojo项目分支,Dojo 基金会提出了 Bayeux 协议用来标准化 Comet 应用中客户端和服务器端之间的通信。Dojox.cometd 实现了 Bayeux 协议的客户端部分,使用 HTTP 长轮询来作为数据的传输通道。

Pushlet:基于HTTP流,而不是AJAX长轮询。一个开源的 Comet 框架,Pushlet 使用了观察者模型:客户端发送请求,订阅感兴趣的事件;服务器端为每个客户端分配一个会话 ID 作为标记,事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。貌似只支持Java。

SingalR:基于AJAX长轮询。ASP.NET团队开发的一个开源的.net framework库和Jquery插件。集成的客户端与服务器库,基于浏览器的客户端和基于 ASP.NET 的服务器组件可以借助它来进行双向多步对话。

五、SingalR的MVC4实践

1.安装与运行环境:(Nuget) install-package Microsoft.AspNet.SignalR ,注意:PM>后面不要有空格。

或者到GitHub上下载源码:https://github.com/SignalR/SignalR

这里顺便提一下,SingalR服务端需要支持的OS:

  • Windows Server 2012
  • Windows Server 2008 r2.
  • Windows 8
  • Windows 7
  • Windows Azure

.net framework4,4.5。WebSocket必须是4.5.

IIS7,7.5 ,integrated Mode,而不是classic Mode, WebSockets必须IIS8。更加详尽的说明,请自行参考:http://www.asp.net/signalr/overview/getting-started/supported-platforms

2.核心实现:

首先,我们需要引用SignalR,用Nuget不需要自己手工添加,应为你的asp.net mvc项目自动添加好一切。

服务端Library:

Microsoft.AspNet.SignalR.Core Microsoft.AspNet.SignalR.Owin Microsoft.AspNet.SignalR.SystemWeb Owin Newtonsoft.Json

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
 
namespace DeepleoComet
{
    public class ChatHub : Hub
    {
        public void Send(string name, string message)
        {
            // Call the addNewMessageToPage method to update clients.
            Clients.All.addNewMessageToPage(name, message);
        }
    }
}

客户端的Jquery插件:

jquery.signalR-1.1.3.min.js.

@{
    ViewBag.Title = "Chat";
}
 
<h2>Chat</h2>
 
<div class="container">
    <input type="text" id="message" />
    <input type="button" id="sendmessage" value="Send" />
    <input type="hidden" id="displayname" />
    <ul id="discussion">
    </ul>
</div>
 
@section scripts {
    <script src="~/Scripts/jquery.signalR-1.1.3.js"></script>
    <script src="~/signalr/hubs"></script>
    <script>
        $(function () {
            var chat = $.connection.chatHub;
            chat.client.addNewMessageToPage = function (name, message) {
                $('#discussion').append('<li><strong>' + htmlEncode(name)
                    + '</strong>: ' + htmlEncode(message) + '</li>');
            };
          
            $('#displayname').val(prompt('Enter your name:', ''));
            $('#message').focus();
            $.connection.hub.start().done(function () {
                $('#sendmessage').click(function () {
                    chat.server.send($('#displayname').val(), $('#message').val());
                    $('#message').val('').focus();
                });
            });
        });
      
        function htmlEncode(value) {
            var encodedValue = $('<div />').text(value).html();
            return encodedValue;
        }
    </script>
}

实现效果:

开两个页面:http://localhost:11968/ ,分别键入name,就可以实现一个简单的聊天室功能了。

六、题外话:Comet的替代品:Html5的WebSocket

在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 flex ajax bridge,可以在javascript中使用这两项功能. 可以预见,如果websocket一旦在浏览器中得到实现,将会替代上面两项技术,得到广泛的使用.面对这种状况,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并达到实时通讯。

真是相见恨晚啊,才知道还有这么个东西,居然Web端也有了全双工的Socket,貌似有个socket.io还支持IE6,我和我的小伙伴们都惊呆了。

比较好的关于WebSocket文章:http://www.cnblogs.com/wei2yi/archive/2011/03/23/1992830.html

参考资料

1.原理:http://www.ibm.com/developerworks/cn/web/wa-lo-comet/

2.DOJO原理与实践:http://www.ibm.com/developerworks/cn/web/wa-lo-w2fpak-comet/

3.淘宝200W长链接测试与优化:http://rdc.taobao.com/blog/cs/?p=1062

4.长连接百科:http://baike.baidu.com/view/2831907.htm

5.博客园Comet专题:http://kb.cnblogs.com/page/112185/

6. Jetty+Dojo+Tomcat:http://blog.csdn.net/garfier/article/details/5942826

7.SingalR官网:http://signalr.net/

8.Singal辅导:http://www.asp.net/signalr

Comet:基于 HTTP 长连接的“服务器推”技术解析的更多相关文章

  1. Comet:基于 HTTP 长连接的“服务器推”技术

    “服务器推”技术的应用 请访问 Ajax 技术资源中心,这是有关 Ajax 编程模型信息的一站式中心,包括很多文档.教程.论坛.blog.wiki 和新闻.任何 Ajax 的新信息都能在这里找到. c ...

  2. 转载:Comet:基于 HTTP 长连接的“服务器推”技术

    转自:http://www.ibm.com/developerworks/cn/web/wa-lo-comet/ 很多应用譬如监控.即时通信.即时报价系统都需要将后台发生的变化实时传送到客户端而无须客 ...

  3. [转载] Comet:基于 HTTP 长连接的“服务器推”技术

    转载自http://www.ibm.com/developerworks/cn/web/wa-lo-comet/ “服务器推”技术的应用 传统模式的 Web 系统以客户端发出请求.服务器端响应的方式工 ...

  4. comet基于HTTP长连接技术(java即时通信,推送技术详解)

    服务器推送技术的基础思想是将浏览器主动查询信息改为服务器主动发送信息,服务器发送一批数据,浏览器显示消息,同时保证与服务器的连接,当服务器需要再一次的发送数据,浏览器显示数据并保持连接. comet基 ...

  5. HTTP长连接实现“服务器推”的技术

    HTTP长连接实现“服务器推”的技术快速入门及演示示例 在我的印象里HTTP是一种“无状态的协议”,也就是不知道以前请求的历史,无法保留上一次请求的结果.Cookie的诞生,弥补了这个不足,浏览器可以 ...

  6. Comet技术详解:基于HTTP长连接的Web端实时通信技术

    前言 一般来说,Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询.Comet技术.WebSocket技术.SSE(Ser ...

  7. 也谈---基于 HTTP 长连接的“服务(转载)

    这里指讨论基于HTTP的推技术, 诸如flash,applet之类的东西不作分析, 他们就不能说是"纯粹"的浏览器应用了. 首先是一点背景知识, 大家都知道长连接避免了tcp连接的 ...

  8. HTTP 笔记与总结(9)分块传输、持久链接 与 反向 ajax(comet / server push / 服务器推技术)

    反向 ajax 又叫 comet / server push / 服务器推技术 应用范围:网页聊天服务器,例如新浪微博在线聊天.google mail 网页聊天 原理:一般而言,HTTP 协议的特点是 ...

  9. Asp.net的服务器推技术 (Server Push)

    在以往的和服务器端通信技术中,我们多数使用的是AJAX轮询式访问,也就是在Javascript中控制时间间隔,然后每隔一段时间就访问一次服务器,然后获得数据或通知.但是这种轮询方式的访问有90%是在做 ...

随机推荐

  1. 【转载】Android 自动化测试 Emmagee

    Emmagee 是一个性能测试小工具 用来监控指定被测应用在使用过程中占用机器的CPU, 内存,流量资源的性能小工具 Emmagee 介绍 Emmagee是网易杭州研究院QA团队开发的一个简单易上手的 ...

  2. Struts 2 Learning

    目录 . J2EE简介 . JAVA EE应用的分层模型 . 搭建Struts2 Demo应用 . struts2流程 . struts2的常规配置 . 实现Action . 配置Action . 配 ...

  3. csc.rsp Invent by Microshaoft

    # This file contains command-line options that the C# # command line compiler (CSC) will process as ...

  4. Sublime Text 3 插件安装及Vim 模式设置

    1.安装Sublime Text 3  下载安装:http://www.sublimetext.com/3 Package Control安装:https://sublime.wbond.net/in ...

  5. JavaScript-分支语句与函数

    一.分支语句-if语句 四种if语句: 1.if(判断条件) { 满足条件时需执行的语句 } 2.if(判断条件) { 满足条件时需执行的语句 } else { 不满足条件时需执行的语句 } 3.if ...

  6. C++基础笔记(四)C++内存管理

    析构函数 * 析构函数在对象所占用内存释放时调用,通常用来释放相关的资源 * 析构函数就是一个特殊的类成员函数,它是构造函数相反 构造函数:对象在分配内存之后,立即调用 析构函数:对象在内存被释放之前 ...

  7. JDBC的几种驱动

    不同的数据库的驱动是不同的 其中:Access驱动串---------sun.jdbc.odbc.JdbcOdbcDriver    MySQL驱动串---------com.mysql.jdbc.D ...

  8. winform 下log4net简单应用示例及“缺少log4net引用”的处理方案

    1.添加应用log4net.dll 2.新增log4net.config文件,文件内容如下 <?xml version="1.0" encoding="utf-8& ...

  9. Center OS mongodb安装

    一.下载        1.#cd /usr/local/src     2.#wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2. ...

  10. 【转】c# yield用法

    注意事项:1.yield语句只能出现在迭代块中:2.yield return 语句不能放在 try-catch 块中的任何位置. 该语句可放在后跟 finally 块的 try 块中3.yield b ...