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

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

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

下图是MSDN关于解释:

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

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;
        }

    }
}

实现效果

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

时间: 2024-09-15 06:30:32

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

WCF 双工模式发布在IIS上 客户端引用不了服务端

问题描述 请问大神们一个问题,我做了一个WCF双工模式,我发布在IIS后客户端引用不了,请问是怎么回事呢?这是服务端配置,这是发布IIS,这是客户端引用文件,这是什么原因呢?已经搞了半个月了都没搞定!急!急!急!!!!!!!!! 解决方案 解决方案二:url后面加?wsdl试试总之只要有wsdl描述就可以引用解决方案三:不是那里的问题?解决方案四:自己顶一下!

利用WCF双工模式实现即时通讯_C#教程

概述  WCF陆陆续续也用过多次,但每次都是浅尝辄止,以将够解决问题为王道,这几天稍闲,特寻了些资料看,昨晚尝试使用WCF的双工模式实现了一个简单的即时通讯程序,通过服务端转发实现客户端之间的通讯.这只是个Demo,没有考虑异常处理和性能问题.解决方案结构如下:   契约 using System; using System.Collections.Generic; using System.Linq; using System.ServiceModel; using System.Text;

WCF 双工模式

WCF之消息模式分为:1.请求/答复模式2.单向模式3.双工模式 其中,请求/答复模式,在博文:  WCF 入门教程一(动手新建第一个WCF程序并部署) WCF 入门教程二 中进行了详细介绍,此处将主要介绍:单向模式与双工模式. 1.首先,先创建一个WCF应用程序: 创建完成后,目录如下: 2.删除IService1.cs和Serivce1.svc,或者修改名称为:CalculateService.svc与ICalculateService.cs后,显示如下: 3.ICalculateServi

WCF双工通讯以及客户端间的间接通讯

原文:WCF双工通讯以及客户端间的间接通讯 由于学习计划安排不当,对WCF的认知一直停滞不前,最近工作上又用回了WCF,重拾一下,看到蒋老师介绍双工通讯的博文,实践一下,积累一下.原想着WCF的双工通讯就是原本的客户端能调用服务端的方法之余,服务端同样也能调用客户端的方法.把博文看了一遍之后发现这个双工实际上是借助了方法回调实现的.那么下面先介绍一下最基本的双工通讯形式,再介绍一下鄙人利用双工通讯设计了一种形式. WCF通讯都是基于方法调用进行信息交互和传递,在开发基本模式的时候也需要往服务端下

WCF TCP双工模式详解介绍

在一个基于面向服务的分布式环境中,借助一个标准的.平台无关的通信协议,使各个服务通过SOAP Message实现相互之间的交互.这个交互的过程实际上就是信息交换的过程.WCF支持不同形式的信息交换,我们把这称之为信息交换模式(Message Exchange Pattern(简称MEP),下同), 常见的MEP包括: 请求/答复,单向模式和双工模式.通过采用双工的MEP,我们可以实现在服务端调用客户端的操作.虽然WCF为我们实现底层的通信细节,使得我们把精力转移到业务逻辑的实现,进行与通信协议无

WinXP如何优化设置网络连接速度与双工模式

  设置前先和大家解释一下什么是双工模式. 双工:信息在两点之间能够在两个方向上同时发送的工作方式. 双工的含义是可以同时进行双向传输,就如平时的在电话中通话那样.像步行对话机这样的设备是半双工或简单双工的. 设置步骤如下: 1.在桌面上找到"网上邻居"的图标,右键单击,选择"属性"; 2.新窗口中会看到"本地连接"的图标,同样点击右键,选择"属性"; 3.在出来的"本地连接 属性"中,单击"配置

lis通讯-西门子VersaCell X3控制台连接LIS,条码双工模式下,数据交互格式是怎样的?

问题描述 西门子VersaCell X3控制台连接LIS,条码双工模式下,数据交互格式是怎样的? 西门子VersaCell X3控制台连接LIS,条码双工模式下,数据交互格式是怎样的?

silverlight:wcf双工通讯学习笔记

一直觉得SL中的wcf双工通讯方式有点鸡肋,如果是以http方式实现则效率太低,如果用SL4中的tcp方式实现,又跟socket太雷同,所以一直没去研究,不过这东西在对性能要求不高时(比如在网页上每5分钟更新一次天气预报/股票信息),实现起来还是蛮方便的. wcf双工通讯与传统的wcf相比,最大的区别就是:传统的wcf通常都是客户端去调服务,即客户端从服务端上"拉"信息,而双工通讯除了允许客户端从服务端"拉"信息外,服务端还能主动向客户端"推"送

菜鸟求助WCF双工的问题

问题描述 服务端:[ServiceContract(SessionMode=SessionMode.Required,CallbackContract=typeof(IQQSback))]publicinterfaceIQQS{[OperationContract(IsOneWay=true,IsInitiating=true,IsTerminating=false)]voidSpeak(stringvalue);[OperationContract(IsOneWay=true,IsInitia