comet在asp.net中的实现

网上有关“服务器推送”的介绍非常多,其中一种实现方式就是采用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),类似如下:

 1 协议类似socket通讯编程中的协议(类似):
2 [4bytes]+[16bytes]+[some]+[1byte]
3 消息类型+消息长度+消息内容+验证位
4
5 (Web Server->Browser方向)json格式数据包 每个包类似C++中的结构体:
6
7 有用户上线:
8 {
9 "type":"login",
10 "login_name":"xiaozhi_5638",
11 "login_time":"2014-04-15 12:34:19"
12 }
13
14 有用户发送消息:
15 {
16 "type":"sendmsg",
17 "msg":"hello world![emo:23]",
18 "send_name":"xiaozhi_5638",
19 "send_time":"2014-04-15 12:34:19"
20 }
21
22 有用户下线:
23 {
24 "type":"logout",
25 "logout_name":"xiaozhi_5638",
26 "logout_time":"2014-04-15 12:34:19"
27 }
28
29 心跳包:
30 {
31 "type":"heartbeat",
32 "time":"2014-04-15 12:34:19"
33 }
34
35 自己登录结果:
36 {
37 "type":"login_result",
38 "result":"true", //or false
39 "online_users":["xiaozhi_5638","somebody","zhangsan"], //登录成功 返回在线用户
40 "time":"2014-04-15 12:34:19"
41 }
42
43 自己发送消息结果
44 {
45 "type":"sendmsg_result",
46 "result":"true", //or false
47 "msg":"hello world![emo:23]",
48 "time":"2014-04-15 12:34:19"
49 }
50
51 数据包集合(上面的都是单个数据包,data_list中包含多个数据包集合) 用于一次性将服务端缓存的数据包传递到browser
52 {
53 "type":"data_list",
54 "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"}] //数组类型 包含多个数据包
55 }
56 Browser->Web Server方向的数据 以普通get/post方式传递

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

 1 function Open_Http_Channel()  //开启一个http通道(http长连接)
2 {
3 $.ajax(
4 {
5 url:"chat_aspx.ashx", //action处理页面
6 type:"post", //数据传递方式
7 data:{"requestType":"a_long_connection","id":$("#input_user_name").val()}, //上传参数
8 dataType:"json", //返回数据类型
9 success:function(data) //解析返回的json包
10 {
11 //接收web server端返回的数据 开始解析数据 参见protocol.txt
12 if(data.type == "login") //有人上线
13 {
14 ShowLogin(data); //显示登录信息
15 }
16 if(data.type == "sendmsg") //有人发送消息
17 {
18 ShowMsg(data.msg,data.send_time,data.send_name); //显示消息
19 }
20 if(data.type == "logout") //有人下线
21 {
22 Logout(data);
23 }
24 if(data.type == "data_list") //数据包集合
25 {
26 for(i in data.list) //遍历数据包集合
27 {
28 if(data.list[i].type == "login")
29 {
30 ShowLogin(data.list[i]); //显示登录信息
31 }
32 if(data.list[i].type == "sendmsg")
33 {
34 ShowMsg(data.list[i].msg,data.list[i].send_time,data.list[i].send_name); //显示消息
35 }
36 if(data.list[i].type == "logout") //下线
37 {
38 Logout(data.list[i]);
39 }
40 //...
41 }
42 }
43 //...
44 //...
45 //...定义的其他协议 在此处解析
46 Open_Http_Channel(); //马上开启第二次http通道
47 },
48 error:function(xhr,info,obj)
49 {
50 Open_Http_Channel(); //马上开启第二次http通道
51 }
52 });
53 }

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

图3

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

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

comet在asp.net中的实现,布布扣,bubuko.com

时间: 2024-10-29 19:06:29

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

asp.ne中使用ajax和controller进行通信问题记录

为了页面显示和后端处理分离,使用了html+ajax+mvc的形式进行处理. 在这其中遇到的问题记录: 1. 在使用ajax向controller请求数据的时候,"get"方法会缓存上一次的请求,导致controller方法不能被debug跟踪到,开始以为是vs出错了,到后来才搞清楚. 解决方法:请求controller路径时加上随机数,或者使用"post"方法. 2. 在使用"POST"方法时,IE11要小心处理,因为ie会出现怎么都执行不了的

ASP.NET中的几种分页

1.通过DataGrid控件实现分页 ASP.NET中的DataGrid控件自带了分页功能,当绑定了DataGrid的数据源之后,须要对DataGrid控件进行一些设置: 左击控件右上角的小箭头→属性生成器: 选择左边的[分页]选项卡 选中[同意分页].[页大小]表示一页显示多少条数据:导航button的[位置]有顶.底.上下型三种选择.[模式]有页码和"上一页.下一页button".假设选择了页码模式.[数值button]表示最多显示的button数量,假设选择了还有一种模式,&qu

asp.net中session的原理及应用

Session简介丶特性 1.Session是一种Web会话中的常用状态之一. 2.Session提供了一种把信息保存在服务器内存中的方式.他能储存任何数据类型,包含自定义对象. 3.每个客户端的Seesion是独立存储的. 4.在整个会话过程中,只要SessionID的cookie不丢失,都会保存Session信息的. 5.Session不能跨进程访问,只能由该会话的用户访问.应为提取Session数据的id标识是以Cookie的方式保存到访问者浏览器的缓存里的. 6.当会话终止,或过期时,服

asp.net中javascript与后台c#交互

asp.net中javascript与后台c#交互 作者:熊猫大叔 字体:[增加 减小] 类型:转载 时间:2015-10-23我要评论,出处:http://www.jb51.net/article/73793.htm 这篇文章主要介绍了asp.net中javascript与后台c#交互,需要的朋友可以参考下 最近做一个小项目,网页中嵌入google maps,输入经纬度坐标可以定位地图位置并加注标记,点击标记获取远端摄像头数据并在视频窗口实现播放.在实际操作过程中,由于经纬度数据和视频登录的用

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

1. sessionState的4种mode模式 在ASP.NET中Session的sessionState的4中mode模式:Off.InProc.StateServer及SqlServer. 2. Off模式 <sessionState mode="Off"></sessionState> 关闭模式,即不需要使用Session. 单个页面关闭Session: <%@ Page EnableSessionState="false" %

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

1. 数据库访问性能优化  数据库的连接和关闭 访问数据库资源需要创建连接.打开连接和关闭连接几个操作.这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资源.ASP.NET中提供了连接池(Connection Pool)改善打开和关闭数据库对性能的影响.系统将用户的数据库连接放在连接池中,需要时取出,关闭时收回连接,等待下一次的连接请求. 连接池的大小是有限的,如果在连接池达到最大限度后仍要求创建连接,必然大大影响性能.因此,在建立数据库连接后只有在真正需要操作时才打开连接,使用完

ASP.NET中的&lt;%%&gt;介绍

一.主要用于ASP.NET前台绑定用的最多: <%#Eval("")%> <%#Bind("")%> <%=变量%> 1.<%#Eval("数据列")%>主要用于需要进行更改的数据列 如:需要将<%Eval("性别")%>=1:将1转换成女. 首先在.CS文件中定义一个方法: 1 public object ChangeSex(object obj) 2 { 3 if

ASP.NET中Cookie跨域的问题及解决代码

ASP.NET中Cookie跨域的问题及解决代码 http://www.liyumei.net.cn/post/share18.html Cookies揭秘  http://www.cnblogs.com/zhangziqiu/archive/2009/08/06/cookies-javascript-aspnet.html 最近在项目开发中遇到一个很棘手的问题,一个用户在顶级域名登录后,跳转到自己所拥有的二级域名下管理二级网站时,cookie丢失了,一直找解决办法找了整整两天,百度谷歌一大堆,

ASP.NET中引用dll“找不到指定模块&quot;的完美解决办法 z

DllImport是System.Runtime.InteropServices命名空间下的一个属性类,其功能是提供从非托管DLL导出的函数的必要调用信息.DllImport属性应用于方法,要求最少要提供包含入口点的dll的名称.DllImport的定义如下: [AttributeUsage(AttributeTargets.Method)] public class DllImportAttribute: System.Attribute { public DllImportAttribute