之前开发基于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 + ', 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; } } }
实现效果
才疏学浅,如有错误,敬请指出。