使用IHttpAsyncHandler实现服务器推送技术

继上次发了一篇博客,ajax的应用以来,这是本菜鸟在博客园的第二篇文章.

由于第一篇博客,大家反映是会的没用,不会的嫌多.那么,这篇博客,不会又丑又长的.只是会简单介绍服务器推模型的好处,以及我自己使用中发现的问题..

我希望大家看了这篇博客,一定要看完,并不是写的多好,因为最后 我会给出web.config的配置节点代码,如果会自己配置的当我没说.

先啰嗦几句话. 在我不会推模型之前,我一直都是拉模型,也就是让js代码每隔一段时间向服务器索取数据,并刷新,当然,肯定是异步刷新..

今天看了看推模型,并写了简单的代码.不多说,如果会拉模型的,感觉感觉comet的妙处吧..

由于本次代码全是手写,不保证没错

<由于几个类都是实现接口,通过配置文件,实现htm页面访问,所以还是看完吧>

(创建一个项目,asp.net web项目.然后创建一个类,继承自IHttpHandler接口,)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

namespace Comet

{

//继承并实现了 IHttpHandler   接口

  public class MyHandler : IHttpHandler   

    {        

//这个属性,和方法 都是实现 IHttpHandler 的

     public bool IsReusable   

        {           

      get { return true; }    

       }

         public void ProcessRequest(HttpContext context)      

     {       

//设置不让客服端缓存

        context.Response.Cache.SetCacheability(HttpCacheability.NoCache);      

         List<MyAsyncResult> userlist = MyAsyncHandler.Queue;

            string sessionId = context.Request.QueryString["sessionId"];     

          string message = context.Request.QueryString["message"];

            foreach(MyAsyncResult res in userlist)            

     {

//如果不是自己就推

                 if (res.SessionId != sessionId)        

          {               

      //激发callback,结束请求      

         res.Message = message;                    

                 res.SetCompleted(true);                  

       }

            }

         }

    }

(接着第二个类,实现IHttpAsyncHandler接口)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

namespace Comet

{

  public class MyAsyncHandler : IHttpAsyncHandler

{

//这个集合 用于存放 所有请求的

  public static List<MyAsyncResult> Queue = new List<MyAsyncResult>();

  public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)

{

   context.Response.Cache.SetCacheability(HttpCacheability.NoCache);

 string sessionId = context.Request.QueryString["sessionId"];

//查找Queue这个集合  SessionId ==传过来的sessionId  !=null

 if (Queue.Find(q => q.SessionId == sessionId) != null) 

{

int index = Queue.IndexOf(Queue.Find(q => q.SessionId == sessionId));

//把HttpContext对象的实例等于当前请求的所有信息

 Queue[index].Context = context;

 Queue[index].CallBack = cb;

return Queue[index];

}

//MyAsyncResult 这个类是 回调的参数类(相当于 你定义一个事件 使用的泛型的   public event EventHandler<MyEvargs> Events;  MyEvargs这个类继承了EventArgs  同样的道理)

 MyAsyncResult asyncResult = new MyAsyncResult(context, cb, sessionId);

 Queue.Add(asyncResult);

return asyncResult;

}

这个方法是这个异步接口的另一个方法

  public void EndProcessRequest(IAsyncResult result)  

       {          

   MyAsyncResult rslt = (MyAsyncResult)result;      

//向别的客服端推送  某个 客服端发送的 信息 

      rslt.Context.Response.Write(rslt.Message);      

       rslt.Message = string.Empty;       

  }

//为什么不实现这个方法  (因为IhttpAsyncHandler接口继承了IHttpHandler这个接口,所以实现接口的时候,就实现了它,但是 我们不管它)

  #region IHttpHandler 成员 不实现

        public bool IsReusable      

   {          

   get { return true; }    

     }

        public void ProcessRequest(HttpContext context)      

   {

        }

        #endregion

}

}

下面是参数类,这个类 比较简单 但是 所有的数据 都是经过这些个参数的,回调 才是关键

using System;

using System.Collections.Generic;

 using System.Linq;

using System.Web;

namespace Comet

{

//就是继承了这个IAsyncResult接口,所以就可以是回调的参数类

     public class MyAsyncResult : IAsyncResult    

{       

//这个接口的实现

    public object AsyncState { get; private set; }

        public System.Threading.WaitHandle AsyncWaitHandle { get; private set; }

        public bool CompletedSynchronously { get { return false; }}

        public bool IsCompleted { get; private set; }       

//一些个参数

    public HttpContext Context { get; set; }    

       public AsyncCallback CallBack { get; set; }  

       public string SessionId { get; set; }      

     public string Message { get; set; }

//构造函数

        public MyAsyncResult(HttpContext context, AsyncCallback cb, string sessionId)    

     {            

    this.SessionId = sessionId;         

      this.Context = context;        

       this.CallBack = cb;       

  }

//这个方法对于的是MyHandler调用哪个方法,

//它的主要作用是,用某种浏览器检测工具,也就是能检测所有请求的工具,就能看出,它是结束当前的请求,在用js马上开始另一个请求,好处就是,感觉这个客服端是长连接的

        public void SetCompleted(bool iscompleted)   

      {      

         this.IsCompleted = iscompleted;     

          if (iscompleted && this.CallBack != null)       

          {

                CallBack(this);          

       }

        }

    }

}

//其实到现在 写的差不多了,我们已经实现了IHttpHandler IHttpAsyncHandler 这两个接口,并处理完了,最麻烦的回调,

剩下的就是,通过一个页面,来调用...  等下看配置文件..其实这个配置文件,已经可以实现了伪静态页面...

新建一个htm页面吧 什么名字无所谓了,代码直接 拿过去,配置文件 一定要配置哦,不然 上面的一切都是扯淡...呵呵

//这些代码

<!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>   

  <title></title>

</head>

<body>   

  <input type="text" id="sessionId" /><input type="button" value="进入" onclick="comin()" /><br />    

 <input type="text" id="message" /><input type="button" value="发送" onclick="send()" />   

  <div id="messages"></div>    

<script type="text/javascript">

        function comin() {         

    var xmlHttp = ajaxFunction();      

       var url = "MyAsyncHandler.ashx?sessionId=" + document.getElementById("sessionId").value;       

      xmlHttp.onreadystatechange = function() {      

           if (xmlHttp.readyState == 4) {             

        if (xmlHttp.status == 200) {             

            document.getElementById("messages").innerHTML += xmlHttp.responseText + "<br>";        

                 //连接已经结束,马上开启另外一个连接     

//看看这句话 呵呵 感觉像无限的 递归

//服务器的一个推 结束,马上开始 继续 一个请求 等待    

                comin();        

             }          

       }        

     }        

     xmlHttp.open("get", url, true);   

          xmlHttp.send(null);    

     }

        function send() {          

   var xmlHttp = ajaxFunction();   

          var url = "MyHandler.ashx?sessionId=" + document.getElementById("sessionId").value + "&message=" + document.getElementById("message").value;       

      xmlHttp.onreadystatechange = function() {       

          if (xmlHttp.readyState == 4) {           

          if (xmlHttp.status == 200) {

                    }               

      else {                

         alert("服务器端错误");      

               }           

      }        

         else {        

             alert("服务器端错误");    

             }          

   }          

   xmlHttp.open("get", url, true);      

       xmlHttp.send(null);     

    }

        function $$(id) {             return typeof id == String ? document.getElementById(id) : id;         }

        function ajaxFunction() {       

      var xmlHttp;          

   try {           

      xmlHttp = new XMLHttpRequest();   

          }       

      catch (e) {      

           try {                

     xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");      

           }               

  catch (e) {       

              try {    

                     xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");   

                  }                

     catch (e) {               

          alert("您的浏览器不支持AJAX!");      

                   return false;           

          }             

    }          

   }        

     return xmlHttp;  

       }   

    </script>

</body>

</html>

放上配置文件的代码

<不要弄错了,,,找到httpHandlers节点,在里面, </httpHandlers>关闭节点的上面加上我给的代码,不然一切都是扯淡...>

(细讲一行)

<!-- add一个节点 verb="*" 这是一个通配符,相当于在 <authorization>节点配置 <allow users="*"/>它一样   -->

<!--path="MyHandler.ashx" 这个意思是 (上面的ajax  open的没有) 本来就是一个不存在的文件  通过配置文件 连接上的,伪静态页面 就是这样做的  -->

<!-- type="Comet.MyHandler"/ 它的意思是  path这个东西指向的类 -->

  <add verb="*" path="MyHandler.ashx" type="Comet.MyHandler"/>  

       <add verb="*" path="MyAsyncHandler.ashx" type="Comet.MyAsyncHandler"/>

啰嗦一句,伪静态页面的配置

<add verb="*" path="hello.htm,hello.html" type="指向实现了IHttpHandler的类"/> 

原文地址:https://www.cnblogs.com/chenmengmeng/p/Comet.html