.net 长连接,实现服务器推送(server push)

服务端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;

namespace WebApplication2
{
    public class MyHandler : IHttpHandler
    {
        /// <summary>
        /// 消息下发请求
        /// </summary>
        /// <param name="context"></param>
        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"] + "    " + userlist.Count.ToString();

            List<string> error = new List<string>();

            foreach (MyAsyncResult res in userlist)
            {

                //如果不是自己就推送信息
                if (res.SessionId != sessionId)
                {

                    res.Message = message;
                    try
                    {
                        //推送内容
                        res.SetCompleted(true);
                    }
                    catch (Exception)
                    {
                        //如果推送失败(客户端已断开,网络异常等)
                        //则删除该标志
                        error.Add(res.SessionId);
                    }

                }

            }

            foreach (var v in error)
            {
                userlist.RemoveAll(fun => fun.SessionId == v);
            }

        }

        public bool IsReusable
        {
            get { return true; }
        }
    }

    public class MyAsyncHandler : IHttpAsyncHandler
    {
        public static List<MyAsyncResult> Queue = new List<MyAsyncResult>();

        public void ProcessRequest(HttpContext context)
        {
        }

        public bool IsReusable
        {
            get { return true; }
        }

        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
        {
            //接到连接请求

            //不让客户端缓存
            context.Response.Cache.SetCacheability(HttpCacheability.NoCache);

            //获取唯一标识
            string sessionId = context.Request.QueryString["sessionId"];

            if (Queue.Count(fun => fun.SessionId == sessionId) > 0)
            {
                int index = Queue.IndexOf(Queue.Find(fun => fun.SessionId == sessionId));
                Queue[index].Context = context;
                Queue[index].CallBack = cb;
                return Queue[index];
            }

            //如果不存在则加入队列
            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;
        }
    }


    public class MyAsyncResult : IAsyncResult
    {
        /// <summary>
        /// 是否结束请求
        /// true:完成
        /// false:阻塞
        /// </summary>
        public bool IsCompleted
        {
            get;
            private set;
        }

        public WaitHandle AsyncWaitHandle
        {
            get;
            private set;
        }

        public object AsyncState
        {
            get;
            private set;
        }

        public bool CompletedSynchronously
        {
            get { return false; }
        }

        public HttpContext Context { get; set; }
        public AsyncCallback CallBack { get; set; }

        /// <summary>
        /// 自定义标识
        /// </summary>
        public string SessionId { get; set; }

        /// <summary>
        /// 自定义消息
        /// </summary>
        public string Message { get; set; }

        public MyAsyncResult(HttpContext context, AsyncCallback cb, string sessionId)
        {
            this.SessionId = sessionId;
            this.Context = context;
            this.CallBack = cb;
            IsCompleted = true;
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="iscompleted">确认下发信息</param>
        public void SetCompleted(bool iscompleted)
        {
            if (iscompleted && this.CallBack != null)
            {
                CallBack(this);
            }
        }
    }
}

 客户端:

<!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("错误:" + xmlHttp.status);

                    }

                }
            }

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

            xmlHttp.send(null);

        }

        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>

 配置文件:

web.Config
 <httpHandlers>
      <add verb="*" path="MyHandler.ashx" type="WebApplication2.MyHandler"/>

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

 </httpHandlers>

 以上代码均测试通过。

摘自:http://blog.chinaunix.net/uid-27875-id-3118211.html

原文地址:https://www.cnblogs.com/comsokey/p/ServicePush.html