今天和一个同事聊到了关于Web(传统)实时通讯的问题,其中包括轮询、长轮询、长连接。最后同事说长轮询对与.net来说比较难以实现(不使用任何框架)。
首先看一下什么是 长轮询 !定义如下:
长轮询:客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。
优点:在无消息的情况下不会频繁的请求。
缺点:服务器hold连接会消耗资源。
以上 长轮询 定义是在网上抄的哦!
那么是不是只要满足以上所诉的内容长轮询是不是就成立呢?那就尝试一下!
建立数据库:
if not exists(select 1 from sys.databases where name='beidoudemo') begin Create Database beidoudemo end go use beidoudemo go if exists(select 1 from sysobjects where name='AjaxPolling' and type='u') begin drop table AjaxPolling end go Create table AjaxPolling ( id int identity Primary key, userName varchar(30) not null, passwordKey varchar(50) not null )
选用Jquery中的AJAX方法发送异步请求,前台省了很多事情了!
具体代码请看:
%@ Page Language= C# AutoEventWireup= true CodeBehind= LongPolling.aspx.cs Inherits= AjaxFinder.LongPolling % !DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd html xmlns= http://www.w3.org/1999/xhtml head runat= server script src= Scripts/jquery-1.4.1.js type= text/javascript /script title /title script type= text/javascript var userID = 0; function SendXHR() { $.ajax({ type: post , //AJAX请求类型 url: LongPollingServer.ashx , //请求url cache: false, //无缓存 timeout: 1000 * 80, //AJAX请求超时时间为60秒 data: { time: 60, userID: userID }, //参数time时间为最多等待(后台保持)时间(60秒无论是否有数据立即返回),单位为秒。userID判断诗句是否为新数据的标识 success: function (data, textStatus) { var obj = document.getElementById( NameDisplay ); //判断返回成功还是失败 如果后台保持连接的时间一到并且没有新数据就会返回fail开头失败的数据 if (data != null data != !(data.indexOf( fail ) != -1)) { var strarr = data.split( , ); // alert(strarr[0]); userID = strarr[0]; obj.innerHTML = 亲!有新用户注册哦!用户名: + strarr[1]; } else { obj.innerHTML = 亲!暂无新用户注册哦 ; } SendXHR();//请求后立即发起AJAX请求 }, error: function (XMLHttpRequest, textStatus, errorThrown) { //New Error do something if (textStatus == timeout ) { //超时间 SendXHR(); } } }); } window.onload = function () { SendXHR(); } /script /head body form id= form1 runat= server div /div div id= NameDisplay /div /form /body /html
前台数据请求已经准备好了,接下来看一下后台代码实现。具体代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Text; using System.Net; using System.Threading; using System.Data; namespace AjaxFinder { /// summary /// AJAX长轮询后台处理页面 /// 主要用于保持连接 /// 有数据返回,无数据继续保持连接超时返回 /// author:bluescreen /// Date :2015-03-14 /// blog:http://www.cnblogs.com/bluescreen/ /// 请不要关注代码编写规范等一些问题。这仅仅是一个DEMO /// 还存在诸多问题 /// /summary public class LongPollingServer : IHttpHandler { public void ProcessRequest(HttpContext context) { /* context.Response.ContentType = text/plain context.Response.Write( Hello World */ int SendTime = 0; //最多等待时间 int userID = 0; //上一次的用户ID if (context.Request.Form[ time ] != null context.Request.Form[ time ].ToString()!= ) { SendTime =int.Parse(context.Request.Form[ time ].ToString());//接收传来的的后台要保持时间 } if (context.Request.Form[ userID ] != null context.Request.Form[ userID ].ToString() != ) { userID = int.Parse(context.Request.Form[ userID ].ToString()); } int i = 0;//计算超时时间(秒) while (true) { Thread.Sleep(1000);//停留一千毫秒(1秒) i++; if (i SendTime) { if (NameStr(userID) != ) { context.Response.Write(NameStr(userID)); break; } } if (i == SendTime) { context.Response.Write( fail:无数据 ); break; } } } /// summary /// 获得用户名 /// /summary /// param name= userID /param /// returns /returns private string NameStr(int userID) { string result = string.Empty; string Sqlstr = select top 1 ID,UserName from AjaxPolling Order by ID desc ; DataSet ds = new DataSet(); ds = SQLHelper.Query(Sqlstr, null); if (ds != null) { if (ds.Tables[0].Rows.Count = 1) { if (int.Parse(ds.Tables[0].Rows[0][0].ToString()) != userID || 0 ==int.Parse(ds.Tables[0].Rows[0][0].ToString())) { result = ds.Tables[0].Rows[0][0].ToString() + , + ds.Tables[0].Rows[0][1].ToString(); } } } return result; } public bool IsReusable { get { return false; } } } }
以上代码经过测试的确符合 长轮询 的说法,那是不是可以说是长轮询呢?各位大牛你们怎么看?