文档章节

comet在asp.net中的实现

IT周见智
 IT周见智
发布于 2015/06/05 17:18
字数 2174
阅读 2
收藏 0

      网上有关“服务器推送”的介绍非常多,其中一种实现方式就是采用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方式传递
View Code

服务端到浏览器端的数据均以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 }
View Code

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

图3

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

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

© 著作权归作者所有

共有 人打赏支持
IT周见智

IT周见智

粉丝 10
博文 61
码字总数 185891
作品 0
西青
私信 提问
Comet服务器推送与SignalR

HTTP协议是一个典型的Request/Response协议,是基于TCP/IP之上的一个应用层协议,该协议最典型的特点就是无状态且需要客户端发起Request服务端才能进行Response,这意味着服务端无法主动“推...

范大脚脚
2017/12/20
0
0
Comet技术原理

来自维基百科:Comet是一种用于web的技术,能使服务器能实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式,长轮询和iframe流。 简单的说是一种基于现有Http协议基...

Airship
2016/11/02
128
1
使用 .NET 实现 Ajax 长连接

作者:http://www.cnblogs.com/cathsfz/ Ajax的长连接,或者有些人所说的Comet,就是指以XMLHttpRequest的方式连接服务器,连接后服务器并非即时写入相应并返回。服务器会保持连接并等待一个...

晨曦之光
2012/03/09
443
0
How ASP.NET MVC Works?[持续更新中…]

一、ASP.NET + MVC IIS与ASP.NET管道 MVC、MVP以及Model2[上篇] MVC、MVP以及Model2[下篇] ASP.NET MVC是如何运行的[1]: 建立在“伪”MVC框架上的Web应用 ASP.NET MVC是如何运行的[2]: URL路...

长平狐
2012/09/04
49
0
AspNetCore中基于Session的身份验证

目录 AspNetCore中基于Session的身份验证 基于Session的身份验证实现 Asp.Net Core中的Session身份认证实现 总结 AspNetCore中基于Session的身份验证 在Asp.Net框架中提供了几种身份验证方式...

guodf
09/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

node安装cnpm

npm install -g cnpm --registry=https://registry.npm.taobao.org

笑丶笑
31分钟前
3
0
OSChina 周三乱弹 —— 夜半回家,推门不动

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @胖达panda :分享陶晶莹/张雨生的单曲《我期待》 《我期待》- 陶晶莹/张雨生 手机党少年们想听歌,请使劲儿戳(这里) @cc_z :熬夜一时爽,...

小小编辑
43分钟前
423
9
验证码

response生成验证码 验证码的作用:防止恶意注册、攻击等 网站上看到的验证码,实际上都是一些图片,而这些图片都是程序(Servlet)生成的! package day19.test; import java.awt.Color; i...

码农屌丝
今天
1
0
day147-2018-11-14-英语流利阅读-待学习

《毒液》刚刚上映,创造漫威宇宙的人却走了 雪梨 2018-11-14 1.今日导读 中国的金庸创造了侠义英雄和江湖传奇,而大洋彼岸的斯坦·李也同样创造了一个绚烂璀璨的漫威宇宙,他构思的每个超级英...

飞鱼说编程
今天
16
0
CentOS 安装PHP5和PHP7

安装PHP5 下载解压二进制包 [root@test-a src]# cd /usr/local/src/[root@test-a src]# wget http://cn2.php.net/distributions/php-5.6.32.tar.bz2[root@test-a src]# tar jxvf php-5.6......

野雪球
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部