[SignalR]SignalR与WCF双工模式结合实现服务端数据直推浏览器端

之前开发基于WinForm监控的软件,服务端基于Wcf实现,里面涉及双工模式,在客户端里面,采用心跳包机制保持与服务端链接,现在有了新需求,需要开发网页版形式,所以怎么保持与服务端链接是重要点,由于数据量比较大,所以不能采用客户端发起请求不断轮询的方式。参考各种资料后,使用SignalR,主要是支持WebSockets通信。并且Hub链接方式解决了realtime 信息交换的功能问题。

下图是MSDN关于解释:

Hub:提供与连接到 Hub 的 SignalR 连接进行通信的方法。

image

Global.asax

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.SessionState;

using System.Web.Routing;

using Microsoft.AspNet.SignalR;

namespace LMSCitySignalR

{

    public class Global : System.Web.HttpApplication

    {



        protected void Application_Start(object sender, EventArgs e)

        {

            RouteTable.Routes.MapHubs();

        }



        protected void Session_Start(object sender, EventArgs e)

        {



        }



        protected void Application_BeginRequest(object sender, EventArgs e)

        {



        }



        protected void Application_AuthenticateRequest(object sender, EventArgs e)

        {



        }



        protected void Application_Error(object sender, EventArgs e)

        {



        }



        protected void Session_End(object sender, EventArgs e)

        {



        }



        protected void Application_End(object sender, EventArgs e)

        {



        }

    }

}

页面代码:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="CityLmsClient.aspx.cs" Inherits="LMSCitySignalR.CityLmsClient" %>



<meta http-equiv="X-UA-Compatible" content="IE=edge" />

<!DOCTYPE html>



<html xmlns="http://www.w3.org/1999/xhtml">



<head runat="server">

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <title>LH CityLMS Client</title>

</head>

<body>

    <div id="dvMsg"></div>

    Client Mac Address:

    <input id="txtMac" type="text" value="50:E5:49:DA:4C:D6" />

    <input id="btnCnLmsSvr" type="button" value="Connect CityLms Server" />

    <br>

    User Name:<input id="txtUserName" type="text" value="admin" />

    User Password:<input id="txtUserPassword" type="password" value="admin" />

    <input id="btnLogin" type="button" value="Login" />

    <br>



    <input id="btnMonitorClientChanel" type="button" value="MonitorClientChanel" />

    <br />

    <input id="btnEmergencyControl" type="button" value="Emergency Control" />

    <br />

    <input id="btnDisConSvr" type="button" value="DisConnect Svr" />

    <script src="Scripts/jquery-1.6.4.js" type="text/javascript"></script>

    <script src="Scripts/json2.js" type="text/javascript"></script>

    <script src="Scripts/jquery.signalR-1.1.1.js" type="text/javascript"></script>



    <script src="/signalr/hubs" type="text/javascript"></script>

    <script type="text/javascript">

        $(function () {



            /*

            *  参考链接:http://www.cnblogs.com/shanyou/archive/2012/07/28/2613693.html

            *· Persistent Connection(HTTP持久链接):持久性连接,用来解决长时间连接的能力,而且还可以由客户端主动向服务器要求数据,而服务器端也不需要实现太多细节,只需要处理 PersistentConnection 内所提供的五个事件:OnConnected, OnReconnected, OnReceived, OnError 和 OnDisconnect 即可。

            *· Hub:信息交换器,用来解决 realtime 信息交换的功能,服务器端可以利用 URL 来注册一个或多个 Hub,只要连接到这个 Hub,就能与所有的客户端共享发送到服务器上的信息,同时服务器端可以调用客户端的脚本,不过它背后还是不离 HTTP 的标准,所以它看起来神奇,但它并没有那么神奇,只是 JavaScript 更强,强到可以用像 eval() 或是动态解释执行的方式,允许 JavaScript 能够动态的加载与执行方法调用而己。

            */

            /*链接对应server端Hub对象*/

            var cityLmsClient = $.connection.cityLmsClientHub;

            cityLmsClient.client.cntServerResult = function (name, message) {

                $('#dvMsg').append('<li><strong>' + (new Date()).toLocaleTimeString() + '-Client Mac Address:' + name

                    + ',&nbsp;&nbsp; Connect CityLms Server Result:' + message + '</strong></li>');

            };

            /*断开连接消息提示*/

            cityLmsClient.client.disConSvr = function (message) {

                alert(message);

            };

            /*操作消息提示*/

            cityLmsClient.client.operateMsg = function (message) {

                $('#dvMsg').append('<li><strong>' + (new Date()).toLocaleTimeString() + '-' + message + '</strong></li>');

            };



            $.connection.hub.start().done(function () {



                /*链接wcf Server*/

                $("#btnCnLmsSvr").click(function () {

                    cityLmsClient.server.conServer($("#txtMac").val());

                });



                /*应急操作*/

                $("#btnEmergencyControl").click(function () {

                    cityLmsClient.server.emergencyControl();

                });

                /*用户登录*/

                $("#btnLogin").click(function () {

                    cityLmsClient.server.userLogin($("#txtUserName").val(), $("#txtUserPassword").val());

                });

                /*启动心跳包,以保持与wcf Server连接*/

                $("#btnMonitorClientChanel").click(function () {

                    cityLmsClient.server.monitorClientChanel();

                });

                /*断开连接*/

                $("#btnDisConSvr").click(function () {

                    cityLmsClient.server.disConnectSvr();

                });

            });

            /*日志显示*/

            $.connection.hub.logging = true;



        });





    </script>



</body>

</html>

cityLmsClientHub.cs代码
using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Reflection;

using System.ServiceModel;

using System.Threading;

using System.Web;

using DL_LMS_Server.Default.Shared;

using DL_LMS_Server.Service.DataModel.Parameter;

using DL_LMS_Server.Service.DataModel.Result;

using Microsoft.AspNet.SignalR;



namespace LMSCitySignalR

{

    public class cityLmsClientHub : Hub

    {

        ServiceCallBack serCallBack = null;

        /// <summary>

        /// 应急操作回调

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void RealTimeCabChCallBackMessage_Event(object sender, LMSClientNotifiedEventArgs e)

        {

            COptRealTimeCabChResult optCabChresult = e.NotifiedMessage as COptRealTimeCabChResult;

            string _sMsg = string.Format("{0}-CabID:{1},byCh1ActType:{2},byCh2ActType:{3},byCh3ActType:{4},byCh4ActType:{5},byCh5ActType:{5},byCh6ActType:{6},CtuLockStatus:{7}",

                DateTime.Now.ToShortTimeString(),

                optCabChresult.CabID,

                optCabChresult.byCh1ActType,

                optCabChresult.byCh2ActType,

                optCabChresult.byCh3ActType,

                optCabChresult.byCh4ActType,

                optCabChresult.byCh5ActType,

                optCabChresult.byCh6ActType,

                optCabChresult.CtuLockStatus);

            Clients.Client(Context.ConnectionId).OperateMsg(_sMsg);

            Clients.Client(Context.ConnectionId).OperateMsg("==========================end======================");

        }

        public void Hello()

        {

            Clients.All.hello();

        }

        private static bool bIsConnect = false;

        private static string sMacAddress = null;

        private static string sUserName = null;

        private static string sUserPassword = null;

        /// <summary>

        ///链接wcf Server

        /// </summary>

        /// <param name="clientMacAddress">mac地址</param>

        /// <returns></returns>

        private CommunResult ConnService(string clientMacAddress)

        {

            CommunResult result = new CommunResult();

            try

            {

                SvrRetMessage svrMessage = ClientComServiceFactory.GetClientServiceFactory.GetClientComService.Connect(clientMacAddress);

                if (!svrMessage.ExcuResult)

                {

                    result.Message = svrMessage.Message;

                    result.CommunState = CommState.NoRegister;

                }

                result.CommunState = CommState.Scuess;

                result.Message = "连接成功";



            }

            catch (EndpointNotFoundException e)

            {

                string mes = e.Message;

                result.CommunState = CommState.Failed;

                result.Message = CommMessage.sNoServer;

            }

            catch (TimeoutException e)

            {

                string mes = e.Message;

                result.CommunState = CommState.TimeOut;

                result.Message = CommMessage.sTimeOuteMessahe;

            }

            catch (Exception e)

            {

                string mes = e.Message;

                result.CommunState = CommState.Failed;

                result.Message = CommMessage.sNoServer;

            }

            return result;

        }

        /// <summary>

        /// 断开与wcf Server链接

        /// </summary>

        public void DisConnectSvr()

        {

            string _sDisConSvrMsg = string.Format("{0}{1}.", sMacAddress, DisConnService().Message);

            Clients.Client(Context.ConnectionId).DisConSvr(_sDisConSvrMsg);

            Debug.Write(_sDisConSvrMsg);

        }

        /// <summary>

        /// 客户端与服务器端断开连接

        /// </summary>

        /// <returns></returns>

        private CommunResult DisConnService()

        {

            CommunResult result = new CommunResult();

            try

            {

                ClientComServiceFactory.GetClientServiceFactory.GetClientComService.DisConnect(sMacAddress);

                result.CommunState = CommState.Scuess;

                result.Message = "断开连接成功";

            }

            catch (EndpointNotFoundException e)

            {

                string mes = e.Message;

                result.CommunState = CommState.Failed;

                result.Message = CommMessage.sNoServer;

            }

            catch (TimeoutException e)

            {

                string mes = e.Message;

                result.CommunState = CommState.TimeOut;

                result.Message = CommMessage.sTimeOuteMessahe;

            }

            catch (Exception e)

            {

                string mes = e.Message;

                result.CommunState = CommState.Failed;

                result.Message = CommMessage.sNoServer;



            }

            return result;

        }

        /// <summary>

        /// 心跳包,保持与wcf server链接

        /// </summary>

        public void MonitorClientChanel()

        {

            if (string.IsNullOrEmpty(sUserPassword) || string.IsNullOrEmpty(sUserName))

                return;

            ThreadPool.QueueUserWorkItem

             (

                delegate

                {



                    while (true)

                    {

                        Thread.Sleep(5000);

                        try

                        {

                            Debug.WriteLine(string.Format("{1}-Client ID:{0}", Context.ConnectionId, DateTime.Now));

                            if (ClientComServiceFactory.GetClientServiceFactory.getObjetcStatus.State == CommunicationState.Faulted)

                            {

                                ClientComServiceFactory.GetClientServiceFactory.getObjetcStatus.Abort();

                                ClientComServiceFactory.GetClientServiceFactory.GetNewClientComService();

                            }



                            ClientComServiceFactory.GetClientServiceFactory.GetClientComService.ReConnect(sMacAddress, sUserName, sUserPassword);



                        }

                        catch (Exception ex)

                        {



                            ClientComServiceFactory.GetClientServiceFactory.GetNewClientComService();

                            Debug.WriteLine(string.Format("Time:{0}-Exception:{1}-Type:{2}", DateTime.Now.ToString("HH:mm:ss"), ex.Message.ToString(), this.GetType().ToString()));

                        }

                    }



                }

              );



        }

        /// <summary>

        /// 链接wcf Server

        /// </summary>

        /// <param name="clientMacAddress">Mac地址</param>

        public void ConServer(string clientMacAddress)

        {

            //DebugerHelper dHelper = new DebugerHelper(DebugParameter.ObtainCalledMethod);

            //dHelper.FormartDebuger("Test");

            CommunResult _comStatus = ConnService(clientMacAddress);

            //FormartDebuger(MethodBase.GetCurrentMethod(), "hello");

            Clients.Client(Context.ConnectionId).CntServerResult(clientMacAddress, _comStatus.Message);

            if (_comStatus.CommunState == CommState.Scuess)

            {

                sMacAddress = clientMacAddress;

                bIsConnect = true;

            }

        }

        /// <summary>

        /// 用户登录

        /// </summary>

        /// <param name="sName">用户名称</param>

        /// <param name="sPassWord">用户密码</param>

        public void UserLogin(string sName, string sPassWord)

        {

            if (CheckConnectStatus())

            {

                LoginResult _serverLoginResult = ClientComServiceFactory.GetClientServiceFactory.GetClientComService.UserLogin(sMacAddress, sName, sPassWord);

                if (_serverLoginResult.UserLoginStatus == LoginStatus.scuess)

                {

                    sUserName = sName;

                    sUserPassword = sPassWord;

                    ServiceCallBack.RealTimeCabChCallBack += RealTimeCabChCallBackMessage_Event;

                }

                Clients.Client(Context.ConnectionId).OperateMsg(string.Format("用户:{0},登录:{1}。", sName, _serverLoginResult.UserLoginStatus == LoginStatus.scuess ? "成功" : "失败,原因:" + _serverLoginResult.LoginMessage));

            }

        }

        /// <summary>

        /// 应急操作

        /// </summary>

        public void EmergencyControl()

        {

            if (CheckConnectStatus())

            {

                OptRealCtuChannelParameter parameter = new OptRealCtuChannelParameter();

                parameter.byCh1ActType = 1;

                parameter.byCh2ActType = 1;

                parameter.byCh3ActType = 1;

                parameter.byCh4ActType = 1;

                parameter.byCh5ActType = 1;

                parameter.byCh6ActType = 1;

                parameter.CabID = "640afa41-b3c6-4c77-bf1b-cf2c4977fbfa";

                parameter.ClientMacAddress = sMacAddress;

                parameter.OptTimeOut = 10000;

                parameter.OptRealDateTime = DateTime.Now;

                parameter.RealTimeStatus = 63;

                SvrRetMessage returnMessage = ClientComServiceFactory.GetClientServiceFactory.GetClientComService.SendOptRealTimeCtuChMessage(parameter, sMacAddress);

                Clients.Client(Context.ConnectionId).OperateMsg(string.Format("CabID:{0},应急控制,操作:{1}。", parameter.CabID, returnMessage.ExcuResult == true ? "成功" : "失败,原因:" + returnMessage.Message));

            }

        }

        /// <summary>

        /// 检查是否已经连接wcf Server

        /// </summary>

        /// <returns></returns>

        private bool CheckConnectStatus()

        {

            if (bIsConnect && !string.IsNullOrEmpty(sMacAddress))

                return true;

            else

                Clients.Client(Context.ConnectionId).OperateMsg("当前还未连接CityLms Server.");

            return false;

        }



    }

}

实现效果

image

image

才疏学浅,如有错误,敬请指出。

你可能感兴趣的:(Signal)