zoukankan      html  css  js  c++  java
  • ASP.NET WebForm(MVC)下实现消息推送(提供简单Demo下载)

    由于项目需要,笔者最近需要实现Web客户端之间的消息的即时推送功能。

    功能描述如下:

    假设A,B,C用户登陆,内存记录下已登录的用户的信息,这时A在所在的客户端(SendInfo.aspx)页面向B发消息,则在B所在客户端页面(SendInfo.aspx)将弹出消息框。

    关键点有两个:

    1.保证客户端和服务端的连接

    2.保证服务端能够向客户端广播消息

    笔者是第一次做这样的实现,所以Google了一些资料,了解到可使用Comet,ajax轮询,WebSocket等技术实现,

    由于时间关系,发现有些技术不是很容易理解,这里做了一个简单Demo.希望能够达到抛砖引玉的作用,与大家分享,共同提高。

    笔者做了两个框架下的实现,ASP.NET Web Form和ASP.NET MVC 下的尝试。

    ASP.NET Web Form版:

    AsyncHandler.cs

    View Code
    using System;
    using System.Collections.Generic;
    using System.Web;
    using System.Threading;
    
    namespace CometSample
    {
        public class WebIMAsyncHandler : IHttpAsyncHandler
        {
            #region IHttpAsyncHandler 成员
    
            public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
            {
                string _UID = context.Request.Params["uid"];
    
                WebIMClientAsyncResult _AsyncResult = new WebIMClientAsyncResult(context, cb, extraData);
    
                string _Content = context.Request.Params["content"];
                string _Action = context.Request.Params["action"];
    
                if (_Action == "login")
                {
                    _UID = context.Request.Params["uid"];
                    _AsyncResult.LoginID = _UID;
                    WebIMMessageHandler.Instance().Login(_UID, _AsyncResult);
                }
                else if (_Action == "logout")
                {
                    _AsyncResult.LoginID = _UID;
                    WebIMMessageHandler.Instance().Logout(_UID, _AsyncResult);
                }
                else if (_Action == "connect")
                {
                    _AsyncResult.LoginID = _UID;
                    WebIMMessageHandler.Instance().Connect(_AsyncResult);
                }
                else if (_Action == "getuserlist")
                {
                    _AsyncResult.LoginID = _UID;
                    WebIMMessageHandler.Instance().GetUserList(_AsyncResult);
                }
                //增加消息发送
                else if (_Action == "sendmsg")
                {
    
                    _AsyncResult.LoginID = _UID;
    
                    //WebIMMessageHandler.Instance().GetUserList(_AsyncResult);
    
                    //调用
                    WebIMMessageHandler.Instance().AddMessage(_Content, _AsyncResult);
    
                }
    
                //调用
                //WebIMMessageHandler.Instance().AddMessage(_Content, _AsyncResult);
                return _AsyncResult;
            }
    
            public void EndProcessRequest(IAsyncResult result)
            {
    
            }
    
            #endregion
    
            #region IHttpHandler 成员
    
            public bool IsReusable
            {
                get { return false; ; }
            }
    
            public void ProcessRequest(HttpContext context)
            {
                throw new NotImplementedException();
            }
    
            #endregion
        }
    
        public class WebIMClientAsyncResult : IAsyncResult
        {
    
            bool m_IsCompleted = false;
            private HttpContext m_Context;
            private AsyncCallback m_Callback;
            private object m_ExtraData;
            private string m_Content;
            private string m_LoginID = string.Empty;
    
    
            public WebIMClientAsyncResult(HttpContext p_Context, AsyncCallback p_Callback, object p_ExtraData)
            {
                this.m_Context = p_Context;
                this.m_Callback = p_Callback;
                this.m_ExtraData = p_ExtraData;
            }
            /// <summary>
            /// 用户编号
            /// </summary>
            public string LoginID
            {
                get
                {
                    return m_LoginID;
                }
                set
                {
                    m_LoginID = value;
                }
            }
            /// <summary>
            /// 发送消息的内容,暂时未使用到
            /// </summary>
            public string Content
            {
                get
                {
                    return m_Content;
                }
                set
                {
                    m_Content = value;
                }
            }
            #region IAsyncResult 成员
    
            public object AsyncState
            {
                get { return null; }
            }
    
            public WaitHandle AsyncWaitHandle
            {
                get { return null; }
            }
    
            public bool CompletedSynchronously
            {
                get { return false; }
            }
    
            public bool IsCompleted
            {
                get { return m_IsCompleted; }
            }
    
            #endregion
    
            /// <summary>
            /// 向客户端响应消息
            /// </summary>
            /// <param name="data"></param>
            public void Send(object data)
            {
                try
                {
                    m_Context.Response.Write(this.Content);
                    if (m_Callback != null)
                    {
                        m_Callback(this);
                    }
                    
                }
                catch { }
                finally 
                {
                    m_IsCompleted = true; 
                }
            }
        }
    }

    MessageHandler.cs

    View Code
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Web;
    using System.Text;
    
    namespace CometSample
    {
        public class WebIMMessageHandler
        {
            private static readonly WebIMMessageHandler m_Instance = new WebIMMessageHandler();
            
            //记录所有请求的客户端
            List<WebIMClientAsyncResult> m_Clients = new List<WebIMClientAsyncResult>();
            //Dictionary<string,WebIMClientAsyncResult> m_Clients=new Dictionary<string,WebIMClientAsyncResult>();
            string m_Users = string.Empty;
            public WebIMMessageHandler()
            {
    
            }
    
            public static WebIMMessageHandler Instance()
            {
                return m_Instance;
            }
    
            /// <summary>
            /// 登录
            /// </summary>
            /// <param name="p_LoginID"></param>
            /// <param name="p_ClientAsyncResult"></param>
            public void Login(string p_LoginID, WebIMClientAsyncResult p_ClientAsyncResult)
            {
                bool _Logined = false;
                foreach (WebIMClientAsyncResult _Item in m_Clients)
                {
                    if (_Item.LoginID == p_LoginID)
                    {
                        p_ClientAsyncResult.Content = "你已登录";
                        _Logined = true;
                        break;
                    }
                }
                if (!_Logined)
                {
                    //m_Clients.Add(p_ClientAsyncResult);
                    p_ClientAsyncResult.Content = "OK";
                }
                p_ClientAsyncResult.Send(null);
    
            }
    
            private string GetUsers()
            {
                /*
                string _Users = string.Empty;
                foreach (WebIMClientAsyncResult _Item in m_Clients)
                {
                    _Users += _Item.LoginID + ",";
                }
                return _Users;
                 */
    
                var sbUsers = new StringBuilder();
                sbUsers.Append("Users:");
    
                foreach (WebIMClientAsyncResult _Item in m_Clients)
                {
                    sbUsers.Append(_Item.LoginID);
                    sbUsers.Append(",");
                }
    
                return sbUsers.ToString();
            }
    
            public void Logout(string p_LoginID, WebIMClientAsyncResult p_ClientAsyncResult)
            {
                foreach (WebIMClientAsyncResult _Item in m_Clients)
                {
                    if (_Item.LoginID == p_LoginID)
                    {
                        m_Clients.Remove(_Item);
                        break;
                    }
                }
                p_ClientAsyncResult.Content = "退出成功";
                p_ClientAsyncResult.Send(null);
                //UpdateUserList();
    
                string _Users = GetUsers();
                foreach (WebIMClientAsyncResult _Item in m_Clients)
                {
                    _Item.Content = _Users;
                    _Item.Send(null);
                }
                m_Clients.Clear();
            }
    
            public void GetUserList(WebIMClientAsyncResult p_ClientAsyncResult)
            {
                Connect(p_ClientAsyncResult);
                string _Users = GetUsers();
                foreach (WebIMClientAsyncResult _Item in m_Clients)
                {
                    _Item.Content = _Users;
                    _Item.Send(null);
                }
                m_Clients.Clear();
            }
    
            public void Connect(WebIMClientAsyncResult p_Client)
            {
                bool _Exists = false;
                foreach (WebIMClientAsyncResult _Item in m_Clients)
                {
                    if (_Item.LoginID == p_Client.LoginID)
                    {
                        _Exists = true;
                        break;
                    }
                }
                if (!_Exists)
                {
                    m_Clients.Add(p_Client);
                }
            }
    
            /*
            public void UpdateUserList()
            {
                string _Users = GetUsers();
                foreach (WebIMClientAsyncResult result in m_Clients)
                {
                    result.Content = m_Users;
                    result.Send(null);
                }
                m_Clients.Clear();
            }*/
    
            /// <summary>
            /// 广播消息
            /// </summary>
            /// <param name="p_Message"></param>
            /// <param name="p_AsyncResult"></param>
            public void AddMessage(string p_Message, WebIMClientAsyncResult p_ClientAsyncResult)
            {
                //保持连接
                if (p_Message == "-1")
                {
                    m_Clients.Add(p_ClientAsyncResult);
                }
                else
                {
                    //将当前请求的内容输出到客户端
                    p_ClientAsyncResult.Content = p_Message;
                    p_ClientAsyncResult.Send(null);
    
                    //否则将遍历所有已缓存的client,并将当前内容输出到客户端
                    foreach (WebIMClientAsyncResult result in m_Clients)
                    {
                        //发送给所有已经登录用户
                        var strMsg = string.Format("{0}{1}{2}{3}{4}",p_ClientAsyncResult.LoginID,"发送给",result.LoginID,"的消息:",p_Message);
                        //result.Content = p_Message;
                        result.Content = strMsg;  
                        result.Send(null);
    
                        //发送给指定用户
                        /*
                        if (string.Equals(result.LoginID, "ZhangShan") && !string.Equals(p_ClientAsyncResult.LoginID, "ZhangShan")) 
                        {
                            var strMsg = string.Format("{0}{1}{2}{3}{4}{5}","Msgs:", p_ClientAsyncResult.LoginID, "发送给", result.LoginID, "的消息:", p_Message);
                            //result.Content = p_Message;
                            result.Content = strMsg;
                            result.Send(null);
                        }
                         */
                    }
    
                    //清空所有缓存
                    m_Clients.Clear();
                }
            }
    
        }
    }

    Login.js

    View Code
    /// <reference path="jquery-1.3.2.min.js" >
    $(document).ready(function () {
    
        //登录,登录成功后,获取在线用户列表,
        function login() {
    
            //增加页面跳转
            var strUrl = '/SendInfo.aspx?strUid=' + $("#txtLoginID").val();
            window.open(strUrl);
        }
    
        $("#btnLogin").click(function () { if ($("#txtLoginID").val() == '') alert('空'); login(); });
    
    
    })

    WebIM.js

    View Code
    /// <reference path="jquery-1.3.2.min.js" >
    //$(document).ready(function () {
    
        //状态,代表是否登录
        //var _logined = false;
    
        //登录,登录成功后,获取在线用户列表,
        function login() {
            //$.post("comet_broadcast.asyn", { action: 'login', uid: $("#txtLoginID").val() },
            $.post("comet_broadcast.asyn", { action: 'login', uid: strUid },
            function (data, status) {
                if (data == "OK") {
                    _logined = true;
                    getuserlist();
    
                    //增加页面跳转
                    /*var strUrl = '\SendInfo.aspx?strUid=' + $("#txtLoginID").val();
                    window.open(strUrl);
                    */
                }
                else {
                    alert(data);
                }
            });
        }
    
        //获取在线用户列表,获取列表后,进入消息等待
        function getuserlist() {
            //$.post("comet_broadcast.asyn", { action: 'getuserlist', uid: $("#txtLoginID").val() },
            $.post("comet_broadcast.asyn", { action: 'getuserlist', uid: strUid },
            function (data, status) {
                //alert('getuserlist' + data);
                var result = $("#divResult");
                result.html(result.html() + "<br/>" + "用户列表:" + data);
    
                wait();
            });
        }
    
        //退出
        function logout() {
            //$.post("comet_broadcast.asyn", { action: 'logout', uid: $("#txtLoginID").val() },
            $.post("comet_broadcast.asyn", { action: 'logout', uid: strUid },
            function (data, status) {
                _logined = false;
                alert(data);
            }
             );
        }
    
        //消息等待,接收到消息后显示,发起下一次的消息等待
        function wait() {
            //$.post("comet_broadcast.asyn", { action: 'connect', uid: $("#txtLoginID").val() },
            $.post("comet_broadcast.asyn", { action: 'connect', uid: strUid },
               function (data, status) {
    
                   /*
                   var result = $("#divResult");
                   result.html(result.html() + "<br/>" + "用户列表:" + data);
                   */
    
                   //2.窗口
                   new Ext.ux.ToastWindow({
                       title: '提示窗口',
                       html: data,
                       iconCls: 'error'
                   }).show(document);
    
                   //服务器返回消息,再次建立连接
                   if (_logined) {
                       wait();
                   }
    
               }, "html");
        }
    
        /***********
        *********************消息发送部分***************************
        ************/
    
        function send() {
    
            //$.post("comet_broadcast.asyn", { action: 'sendmsg', uid: $("#txtLoginID").val(), content: $("#content").val() },
            $.post("comet_broadcast.asyn", { action: 'sendmsg', uid: strUid, content: $("#content").val() },
            function (data, status) {
    
                /*
                var result = $("#divResult");
                result.html(result.html() + "<br/>" + "已发消息:" + data);
                */
    
                //发送方页面提示
                //潜规则:暂时不处理
                /*
                //2.窗口
                new Ext.ux.ToastWindow({
                    title: '提示窗口',
                    html: data,
                    iconCls: 'error'
                }).show(document);
                */
    
            }, "html"
            );
    
            //向comet_broadcast.asyn发送请求,消息体为文本框content中的内容,请求接收类为AsnyHandler
            //$.post("comet_broadcast.asyn", { content: $("#content").val() });
    
            //清空内容
            $("#content").val("");
        };
    
        /**
        * 获取字符串中某个特殊字符首次出现的位置之前的子串
        */
        function GetSubStrBySpecChar(strConnStr,strSplit){
        
        var arrStr = strConnStr.split(strSplit);
        var strSubStr = arrStr[0];
        
        return strSubStr;
    
        }

    Default.aspx

    View Code
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CometSample._Default" %>
    
    <!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">
        <title></title>
    
        <script src="Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
        <script src="Scripts/Login.js" type="text/javascript"></script>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:Label ID="Label1" runat="server" Text="帐号"></asp:Label>
            <input id="txtLoginID" type="text" />
            <input id="btnLogin" type="button" value="Login" />
            <br />
            <div id="divUserList">
            </div>
        </div>
        </form>
    </body>
    </html>

    SendInfo.aspx

    View Code
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SendInfo.aspx.cs" Inherits="CometSample.SendInfo" %>
    
    <!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">
        <title>SendInfo</title>
        <script src="Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
        <script src="Scripts/WebIM.js" type="text/javascript"></script>
    
        <link href="Scripts/ext-3.4.0/resources/css/ext-all.css" rel="stylesheet" type="text/css" />
        <script src="Scripts/ext-3.4.0/adapter/ext/ext-base.js" type="text/javascript"></script>
        <script src="Scripts/ext-3.4.0/ext-all.js" type="text/javascript"></script>
        <script src="Scripts/ToastWindow.js" type="text/javascript"></script>
    
    
        <script language="javascript" type="text/javascript">
    
            var strUid = "<%=strUid %>";
    
            $(document).ready(function () {
    
                //状态,代表是否登录
                var _logined = false;
    
                //alert(strUid);
                //getuserlist_send();
                login();
    
                $("#btnSend").click(function () { send(); })
    
                $("#content").keypress(function (e) {
    
                    var keyCode = null;
    
                    if (e.which)
                        keyCode = e.which;
                    else if (e.keyCode)
                        keyCode = e.keyCode;
    
                    if (keyCode == 13) {
    
                        send();
    
                        return false;
                    }
    
                    return true;
                });
            })
                   
        </script>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <div id="divUserList">
            </div>
            <br />
            广播内容:
            <input type="text" id="content" /><br />
            消息记录:
            <div id="divResult">
            </div>
            <input type="button" id="btnSend" value="广播" />
        </div>
        <div>
            <input id="btnLogout" type="button" value="注销" onclick="logout();"/></div>
        </form>
    </body>
    </html>

    最后还需要关注的是配置文件中的路径

    在web.config 文件的system.web之间加上

    <httpHandlers>
                <add path="comet_broadcast.asyn" type="CometSample.WebIMAsyncHandler" verb="POST,GET"/>
            </httpHandlers>

    好了运行程序,

    效果如下:

    登陆之后,跳转到sendinfo页面

    笔者打开连个浏览器,模拟两个客户端登陆,并且模拟广播消息(能够广播,那么向指定客户端发消息也就很容易了)

    我们可以看到在页面右下角,有消息弹出

    在.NET WebForm下笔者实现了客户端之间即时消息的推送,

    但是在.NET MVC 2 下遇到了一些问题,因为mvc框架下对 ,NET WebForm中某些东西不支持。

    各位看官,若有在MVC2下的实现,多多交流和分享哈! 

    源码下载

    Demo1

    Demo2

  • 相关阅读:
    九省联考2018 IIIDX
    WC2020 猜数游戏
    Gym101821D Search Engine
    Gym102586B Evacuation
    Gym102576D Clique
    UOJ498 新年的追逐战
    LOJ6703 小 Q 的序列
    Codechef A Leisurely Journey
    LG5050 多项式多点求值 和 LG5158 多项式快速插值
    PE427 n-sequences 和 ZJOI2020 抽卡
  • 原文地址:https://www.cnblogs.com/lucky_hu/p/2954989.html
Copyright © 2011-2022 走看看