zoukankan      html  css  js  c++  java
  • 使用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的类"/> 

  • 相关阅读:
    (转)程序员应该知道的10个eclipse调试技巧
    Hibernate缓存
    【转】Hibernate 原汁原味的四种抓取策略
    hibernate 延迟加载和抓取策略
    移动端接口安全
    Thinkphp3.2.3中的RBAC权限验证
    单例模式--工厂模式
    php爬虫入门
    php爬虫入门
    .htaccess使用方法介绍
  • 原文地址:https://www.cnblogs.com/chenmengmeng/p/Comet.html
Copyright © 2011-2022 走看看