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

简介: 原文:[SignalR]SignalR与WCF双工模式结合实现服务端数据直推浏览器端之前开发基于WinForm监控的软件,服务端基于Wcf实现,里面涉及双工模式,在客户端里面,采用心跳包机制保持与服务端链接,现在有了新需求,需要开发网页版形式,所以怎么保持与服务端链接是重要点,由于数据量比较大,所以不能采用客户端发起请求不断轮询的方式。
原文: [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

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

目录
相关文章
|
8月前
|
Web App开发 Windows
让网页自动调用双核浏览器的极速模式
让网页自动调用双核浏览器的极速模式
68 0
|
2天前
|
Web App开发 数据可视化 测试技术
Selenium Headless模式:无头浏览器的使用与优势
Selenium Headless模式是无界面的自动化测试方式,适用于Chrome和Firefox等浏览器,提供更快的速度、更高的隐秘性和资源节省。在Python中启用该模式,需导入Options并设置相关参数。示例代码展示了如何在无头模式下访问网站、执行点击和输入操作。这种模式提升了测试效率和稳定性,尤其适合大规模测试和CI环境。
57 1
|
2天前
|
存储 Web App开发 缓存
通俗科普:服务器端、用户浏览器端与数据存放
通俗科普:服务器端、用户浏览器端与数据存放
20 0
|
9月前
|
数据采集 JavaScript 前端开发
利用无头浏览器进行APP提取数据的技术与实践
利用无头浏览器进行APP提取数据的技术与实践
|
2天前
|
Web App开发 Windows
Windows【Chrome浏览器 02】Auto Dark Mode for Web Contents 无需安装插件开启chrome浏览器黑暗模式
Windows【Chrome浏览器 02】Auto Dark Mode for Web Contents 无需安装插件开启chrome浏览器黑暗模式
105 0
|
2天前
|
JavaScript
sgSpeedMode.js判断360浏览器是“兼容模式”,提示使用“极速模式”
sgSpeedMode.js判断360浏览器是“兼容模式”,提示使用“极速模式”
|
5月前
|
前端开发 JavaScript Java
Web应用中浏览器与服务端的编码和解码
Web应用中浏览器与服务端的编码和解码
77 0
|
7月前
|
Windows
WCF服务端调用客户端.
WCF服务端调用客户端.
|
7月前
|
Windows
|
9月前
|
JavaScript 前端开发 Java