网上有关“服务器推送”的介绍非常多,其中一种实现方式就是采用comet技术,在浏览器与服务端之间建立一个http协议的“长连接”,所谓“长连接”,就是指浏览器到服务端的http请求不会马上得到服务端的应答,而是当满足一定条件的时候,服务器端才“主动”将数据返回给浏览器,这时候一次http请求才完成,普通http连接与http长连接见下图:

图1

如上图,左边为一般http连接,服务端收到浏览器的http请求后会立即做出应答,右边为http长连接,服务端收到浏览器的http请求后,如果有数据需要返回,则立即返回,否则,服务端会“维持住”这个http请求,也就是说,服务端冻结了该次http请求,直到服务端有数据需要返回给浏览器或者超时,服务端才“解冻”该次http请求,这时候,一次“浏览器->服务端”的http请求才完整结束。

“长连接”的作用很明显,它能让服务端“主动”(注意这里的主动加了双引号)将数据发送给浏览器,是的,你没听错,传统的Web程序只能是浏览器主动请求服务端,服务端再作出应答,而现在,服务端居然可以“主动推送”数据给浏览器了。既然服务端现在可以“主动推送”数据给浏览器,那么我们可以完成许多之前不能做到的事情,比如“即时通讯”、“实时监控”等类似客户端需要实时更新数据的应用程序了。这里插一句,如果不采用服务端“主动推送”的方式,我们确实可以按照传统浏览器端使用ajax主动循环请求服务端,来实现所谓的“实时”更新数据的效果,比如每秒ajax请求服务端,来刷新界面数据,但是这种方式的缺点可想而知,不管服务端有没有需更新的数据,浏览器都必须不断地循环去请求(有关ajax轮询的缺点请参考网上其他文章)。

具体实现comet的关键有以下几点:

1)服务端不会立即响应浏览器的http请求(除非当时有数据需要返回给浏览器);

2)浏览器处理完服务端返回的数据后,要立即重新建立一个“http长连接”,供下次使用;

3)浏览器在处理服务端返回的数据时(下一次长连接建立之前),如果服务端有新的数据需要发送给浏览器,那么服务端必须将这些新数据保存起来,等下次“长连接”建立后,再一起发送给浏览器;

4)要想服务端能够实时地、不断地“主动推送”数据到浏览器,浏览器与服务端之间必须无时无刻保持一条“http通道”(也就是http长连接),服务端能够借助该通道将数据返回给浏览器;

5)浏览器一接收到服务端返回的数据,一次“http长连接”就结束了,需要重新建立下一个。

如果我们以socket编程的角度看“http长连接”,它会是这样的:

图2

如上图,每个browser必须时刻存在一个http下行通道(服务端->浏览器,图中(1)处),这样任何时候服务端都能“主动推送”数据给browser,同时,每个浏览器均可以发起其他正常http请求(图中(2)处),这样一来,1号浏览器通过普通http请求发送数据(get/post方式)给服务端,服务端就可以立马将数据“推送”给2号浏览器(使用http下行通道),没错,这不就是socket编程吗?

asp.net中可以使用“异步编程模型”(APM)简单地实现comet,具体涉及到IHttpAsyncHandler接口以及它的BeginProcessRequest和EndProcessRequest两个方法,当我们接收到来自浏览器发起的“http长连接”请求时,我们只调用IHttpAsyncHandler.BeginProcessRequest方法去异步处理,由于我们不立即调用IHttpAsyncHandler.EndProcessRequest方法,所以这个http请求不会立马结束(也就是说,该请求被服务端冻结住了),等服务端有数据时,我们再通过类似Response.Write()方法将数据发送给浏览器,同时调用IHttpAsyncHandler.EndProcessRequest方法结束异步处理http请求,这时候,浏览器端会接收到服务端“主动推送”的数据,浏览器端一次完整的http请求到此时才结束,紧接着,浏览器端通过脚本再次发起一个“http长连接”的请求,依次循环。

文章最后上传一个即时通讯的demo,每个登录的用户都可以发送消息,在线用户均能及时收到服务端“推送”来的数据(包括上线、下线以及消息内容等),由于服务端发送的数据种类比较多,我简单的指定了一个协议(protocol),类似如下:

 协议类似socket通讯编程中的协议(类似):
[4bytes]+[16bytes]+[some]+[1byte]
消息类型+消息长度+消息内容+验证位 (Web Server->Browser方向)json格式数据包 每个包类似C++中的结构体: 有用户上线:
{
"type":"login",
"login_name":"xiaozhi_5638",
"login_time":"2014-04-15 12:34:19"
} 有用户发送消息:
{
"type":"sendmsg",
"msg":"hello world![emo:23]",
"send_name":"xiaozhi_5638",
"send_time":"2014-04-15 12:34:19"
} 有用户下线:
{
"type":"logout",
"logout_name":"xiaozhi_5638",
"logout_time":"2014-04-15 12:34:19"
} 心跳包:
{
"type":"heartbeat",
"time":"2014-04-15 12:34:19"
} 自己登录结果:
{
"type":"login_result",
"result":"true", //or false
"online_users":["xiaozhi_5638","somebody","zhangsan"], //登录成功 返回在线用户
"time":"2014-04-15 12:34:19"
} 自己发送消息结果
{
"type":"sendmsg_result",
"result":"true", //or false
"msg":"hello world![emo:23]",
"time":"2014-04-15 12:34:19"
} 数据包集合(上面的都是单个数据包,data_list中包含多个数据包集合) 用于一次性将服务端缓存的数据包传递到browser
{
"type":"data_list",
"list":[{"type":"login","login_name":"xiaozhi_5638","login_time":"2014-04-15 12:34:19"},{"type":"sendmsg","msg":"hello world!","send_name":"xiaozhi_5638","send_time":"2014-04-15 12:34:19"}] //数组类型 包含多个数据包
}
Browser->Web Server方向的数据 以普通get/post方式传递

服务端到浏览器端的数据均以json格式传递,浏览器到服务端采用jquery写好的ajax库方式。浏览器端的脚本只需要解析服务端传递回来的json数据,然后更新界面,紧接着发起下一个“http长连接”请求。js脚本发起http长连接代码如下:

 function Open_Http_Channel()  //开启一个http通道(http长连接)
{
$.ajax(
{
url:"chat_aspx.ashx", //action处理页面
type:"post", //数据传递方式
data:{"requestType":"a_long_connection","id":$("#input_user_name").val()}, //上传参数
dataType:"json", //返回数据类型
success:function(data) //解析返回的json包
{
//接收web server端返回的数据 开始解析数据 参见protocol.txt
if(data.type == "login") //有人上线
{
ShowLogin(data); //显示登录信息
}
if(data.type == "sendmsg") //有人发送消息
{
ShowMsg(data.msg,data.send_time,data.send_name); //显示消息
}
if(data.type == "logout") //有人下线
{
Logout(data);
}
if(data.type == "data_list") //数据包集合
{
for(i in data.list) //遍历数据包集合
{
if(data.list[i].type == "login")
{
ShowLogin(data.list[i]); //显示登录信息
}
if(data.list[i].type == "sendmsg")
{
ShowMsg(data.list[i].msg,data.list[i].send_time,data.list[i].send_name); //显示消息
}
if(data.list[i].type == "logout") //下线
{
Logout(data.list[i]);
}
//...
}
}
//...
//...
//...定义的其他协议 在此处解析
Open_Http_Channel(); //马上开启第二次http通道
},
error:function(xhr,info,obj)
{
Open_Http_Channel(); //马上开启第二次http通道
}
});
}

其他具体详细的说明参见源代码。效果图一张图3(gif表情没有解析替换,直接显示的文本)

图3

源码地址:http://files.cnblogs.com/xiaozhi_5638/comet_in_aspnet.rar  vs2008

用到了jquery以及跟它相关的几个界面库。注意不要在同一个浏览器上登录太多用户,因为浏览器会为每个用户维持一个http连接,而浏览器对http请求数量有限制(笔者用的chrome上限为6个),超过上限的话,之后所有http请求都会被阻塞。

comet在asp.net中的实现的更多相关文章

  1. ASP.NET中常用的优化性能的方法

    1. 数据库访问性能优化 数据库的连接和关闭 访问数据库资源需要创建连接.打开连接和关闭连接几个操作.这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资源.ASP.NET中提供了连接池( ...

  2. asp.net中ashx生成验证码代码放在Linux(centos)主机上访问时无法显示问题

    最近有个项目加入了验证码功能,就从自己博客以前的代码中找到直接使用,直接访问验证码页面报错如下: 源代码:asp.net中使用一般处理程序生成验证码 Application Exception Sys ...

  3. ASP.NET中Session的sessionState 4种mode模式

    1. sessionState的4种mode模式 在ASP.NET中Session的sessionState的4中mode模式:Off.InProc.StateServer及SqlServer. 2. ...

  4. Asp.net中存储过程拖拽至dbml文件中,提示无法获得返回值

    Asp.net中存储过程拖拽至dbml文件中,提示无法获得返回值,去属性表中设置这时候会提示你去属性表中更改返回类型. 其实存储过程返回的也是一张表,只不过有时候存储过程有点复杂或者写法不规范的话不能 ...

  5. ASP.NET中后台数据和前台控件的绑定

    关于ASP.NET中后台数据库和前台的数据控件的绑定问题 最近一直在学习个知识点,自己创建了SQL Server数据库表,想在ASP.NET中连接数据库,并把数据库中的数据显示在前台,注意,这里的数据 ...

  6. asp.net中缓存的使用介绍一

    asp.net中缓存的使用介绍一 介绍: 在我解释cache管理机制时,首先让我阐明下一个观念:IE下面的数据管理.每个人都会用不同的方法去解决如何在IE在管理数据.有的会提到用状态管理,有的提到的c ...

  7. ASP.NET中Ajax的用法

    在ASP.NET中应用Ajax的格式如下: 前台代码(用JQuery库) $.ajax({ type: "POST", async: true, url: "../Aja ...

  8. Asp.Net中使用OpenRowSet操作Excel表,导入Sql Server(实例)

    有两种接口可供选择:Microsoft.Jet.OLEDB.4.0(以下简称 Jet 引擎)和Microsoft.ACE.OLEDB.12.0(以下简称 ACE 引擎). Jet 引擎大家都很熟悉,可 ...

  9. Asp.net中static变量和viewstate的使用方法(谨慎)

    在.Net平台下进行CS软件开发时,我们经常遇到以后还要用到某些变量上次修改后的值,为了简单起见,很多人都习惯用static来定义这些变量,我也是.这样非常方便,下一次调用某个函数时该变量仍然保存的是 ...

随机推荐

  1. Winform主窗体设计

    主窗体顶部为菜单按钮,子窗体内嵌入Panel显示 界面如下: 第二步,主窗体离不开的几个方法 1,点击菜单功能,加载子窗体 private void btnOpenForm_Click(object ...

  2. WIN2003使用IP安全策略只允许指定IP远程桌面连接

    一,新建IP安全策略 WIN+R打开运行对话框,输入gpedit.msc进入组策略编辑器. 依次打开“本地计算机”策略--计算机配置--Windows设置--安全设置--IP安全策略,在 本地计算机上 ...

  3. Centos 基础开发环境搭建之Maven私服nexus

    hmaster 安装nexus及启动方式 /usr/local/nexus-2.6.3-01/bin ./nexus status Centos 基础开发环境搭建之Maven私服nexus . 软件  ...

  4. C语言的关键字,标示符以及数据类型

      1. 关键字 1>     关键字就是C语言提供的有特殊含义的符号,也叫做“保留字” 2>     C语言一共提供了32个关键字,这些关键字都被C语言赋予了特殊含义 auto doub ...

  5. 今天工作中遇到的问题!echart.js

    echart.js 引用的时候, 配置文件和引用的echart.js  应该放在main.js的后面,带有window.onload的js后面.这样的话,不会阻止echar.js的渲染.

  6. wifi,网关相关标识的获取

    获取WIFI的相关信息 - (void)getWifiInfo { NSArray *ifs = (__bridge_transfer NSArray *)CNCopySupportedInterfa ...

  7. adb devices 端口占用

    一. 1.通过cmd命令,输入adb devices查看连接设备时,报错 2 .通过adb nodaemon server  查看adb server绑定的端口.提示“通过每个套接字地址只能使用一次” ...

  8. 【Java学习笔记】其他对象API

    System类 package p1; import java.util.Properties; import java.util.Set; public class SystemDemo { pri ...

  9. css之滚动条

    overflow:auto; overflow-x:auto; overflow-y:auto;

  10. 模拟XShell的小项目

    不知道大家有没有用过XShell这款工具,这款工具通过windows可以远程操作处于开机状态的linux操作系统,也就是说把你的电脑和一台服务器连入网络,你通过输入服务器所在的IP地址建立一个会话就可 ...