很久都没有写博客了,从15年4月份一直忙到现在,我才有时间去做梳理和总结,因为我提离职了,感觉整个世界突然变得不一样,随着而来的就是心情的放松,写一篇文章也是对过去一年多工作的梳理,加深印象 积累和沉淀。
因为从事的公司是建筑行业的公司,产品也是基于建筑管理体系,整体的项目包含了web端、客户端、服务端,以及因为产品功能需要的一些工具类的软件。在这种多系统的体系结构之下,我们需要进行多个系统之间的实时通讯,其实做到实时通讯的方式有很多种
1.sql server的Server_borker 数据变更通知,是基于sql server数据库的,表中的数据变更会通知到监听的那端,但是觉得考虑到通讯比较频繁,通讯端比较多,这种方式很容易造成代码上和程序上的混乱,不做考虑。
2.wcf的消息广播 相比第一种,这个对于这种多系统通讯更加不具备优势。这种在服务端进行操作,客户端通过注册来监听服务端处理的进度很明显不适合两个或者多个客户端之间的通信,我们的系统可不仅仅限于客户端服务端这么简单,不做考虑。
3..NetMQ 就是本章中要介绍的解决多系统通讯问题的杀手锏了。这个其实在最开始是我们同事去下载研究的,在之后经过一些包装可以很方便的去使用,接下来我们去一起了解一下。
下载地址:http://www.codeproject.com/Articles/193611/DotNetMQ-A-Complete-Message-Queue-System-for-NET
简单的画个图可以更加方便的去了解这个结构
通过这个图我们可以看到,在多个客户端通讯之前需要先开启服务,然后通过唯一性的token我们就可以做到客户端之间的信息通讯。
下载下来的应该是一个服务的启动程序和一个管理端,经过包装和更改更加方便使用一些:
两个服务
1..NETMQ本身的服务
2.添加令牌的服务,开放成对外的wcf接口,可以通过接口取添加令牌。
关于服务配置其实修改后只需要服务端口就行了,连接通过地址和端口号就可以连接。
最后就是令牌了,令牌就是客户端之间通讯的一个token,就是一个唯一的识别信息,就跟qq一样,给妹子发信息总要知道人家的qq号吧,token其实也可以这么理解。
客户端上线之后就客户端连接就是1。
通过上述的描述我想基本都对这个有一个印象了,通过这些印象我们可以想象到他的应用场景,比如去做一个聊天工具,做上传下载的进度提示,等等。
了解了应用场景我们就应该去想想我们怎么样才能简单而又方便的把它应用在我们的项目中,可以解决我们产品和项目中的实际问题。
服务端:
图中可以看到,我们下载下来的.NETMQ在服务端只需要引用这三个库就可以了,
MQServer就是我们针对实际项目应用做的一些修改,将服务开启、停止、令牌的添加删除以及管理都在这里做了包装,只需要去引用就可以了。
/// <summary>/// 消息中心服务器端管理类/// </summary>public class MQService{#region 单例private static MQService _instance;/// <summary>/// 单例/// </summary>public static MQService Instance{get{if (_instance == null){_instance = new MQService();}return _instance;}}#endregion#region 字段MDSServer server;MDSController controller;#endregion#region 属性/// <summary>/// 服务是否处于开启状态/// </summary>public bool IsOpened { get; set; }#endregion#region 构造方法public MQService(){server = new MDSServer();}#endregion #region 开启服务/// <summary>/// 开启服务/// </summary>public void Start(){try{server.Start();IsOpened = true;controller = new MDS.Management.MDSController(AppConfig.Config.MessageServiceIP, AppConfig.Config.MessageServicePort);controller.Connect();}catch (Exception ex){throw ex;}}#endregion#region 关闭服务/// <summary>/// 关闭服务/// </summary>public void Stop(){try{if (IsOpened){server.Stop(true);IsOpened = false;controller.Disconnect();}}catch (Exception ex){throw ex;}}#endregion#region 添加令牌public bool AddToken(string token){try{controller.SendMessage(new AddNewApplicationMessage{ApplicationName = token});return true;}catch{return false;}}#endregion #region 删除令牌public void RemoveToken(string token){var message = controller.SendMessageAndGetResponse(new RemoveApplicationMessage{ApplicationName = token});}#endregion #region 获取令牌列表public ObservableCollection<TokenClass> GetTokenList(){ObservableCollection<TokenClass> result = new ObservableCollection<TokenClass>();//Send a message to MDS server to get list of client applications, get response and fill data grid.var message = controller.SendMessageAndGetResponse(new GetApplicationListMessage());if (message.MessageTypeId != ControlMessageFactory.MessageTypeIdGetApplicationListResponseMessage){throw new MDSException("Response message to GetApplicationListMessage must be a GetApplicationListResponseMessage");}var applicationListMessage = message as GetApplicationListResponseMessage;if (applicationListMessage == null){throw new MDSException("Incorrect message type. MessageTypeId = " + message.MessageTypeId + ", but Type of object: " + message.GetType().Name);}MDS.Communication.Messages.ControllerMessages.GetApplicationListResponseMessage.ClientApplicationInfo[] applications = applicationListMessage.ClientApplications; foreach (var application in applications){TokenClass tc = new TokenClass();tc.TokenName = application.Name;tc.TokenConnect = application.CommunicatorCount;result.Add(tc);}return result;}#endregion}
服务端简单的使用就是这些,详细的介绍以及内部原理网上很多,这里就不介绍了。
客户端:
关于客户端呢,为了便于更方便的使用我写一个简单的demo去演示一下。
图中红框的部分其实就是MDSCommonLib这个库,下面几个类就是对外的事件和方法的包装,我们可以看一下代码:
public class MQMessage{CommunicationClient client;public readonly static MQMessage Instance = new MQMessage();public MQMessage(){//FileTransfer.BLL.XmlReader.ReadXmlInfo();client = new CommunicationClient();client.OnMessageReceived += client_OnMessageReceived;client.OnResponseMessageReceived += client_OnResponseMessageReceived;}/// <summary>/// 接收消息事件/// </summary>public event EventHandler OnMessageReceived;/// <summary>/// 接收消息回执事件/// </summary>public event EventHandler OnResponseMessageReceived;/// <summary>/// 接收消息事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>void client_OnResponseMessageReceived(object sender, MessageReceiveEventArgs e){if (OnResponseMessageReceived != null){OnResponseMessageReceived(sender, e);}}/// <summary>/// 接收消息回执事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>void client_OnMessageReceived(object sender, MessageReceiveEventArgs e){if (OnMessageReceived != null){OnMessageReceived(sender, e);}}/// <summary>/// 发送消息/// </summary>/// <param name="messageContent"></param>public void SendMessage(string messageContent, string tokenName){client.SendMessage(messageContent, tokenName);}/// <summary>/// 开启服务/// </summary>public void Start(string tokenName){client.StartConnection("127.0.0.1", 10905, tokenName);}/// <summary>/// 关闭服务/// </summary>public void Stop(){client.StopConnection();}}
这是最外层的包装,通过这些就可以去调用
MQClientLib.MQMessage.Instance.Start("User_Sean");
客户端开启连接的方式仅仅这样就可以了,通过这行表示:User_Sean上线了。
这样我们在服务端就可以看到User_Sean的连接:
呐,这是一个客户端,如果是多个客户端连接上了呢? 我们就可以通过
/// <summary>/// 发送消息/// </summary>/// <param name="messageContent"></param>public void SendMessage(string messageContent, string tokenName){client.SendMessage(messageContent, tokenName);}
调用这行代码去向其它客户端发送信息,其它客户端接收到信息的时候也会触发这边的回执事件。
/// <summary>/// 接收消息回执事件/// </summary>public event EventHandler OnResponseMessageReceived;
通过注册这个事件,在对方接收到你发送的消息的时候,可以触发这个事件。
/// <summary>
/// 接收消息事件
/// </summary>
public event EventHandler OnMessageReceived;
这个是用来接收别人给你发送的信息的,信息通过这个时间的sender传递过来。
使用暂时就这些,因为代码是加密的,所以只能以后去重新做一下然后给各位提供下载地址了。
当然,关于mq的使用dotNetMQ只是其中一项,今天介绍的也只是通讯,之后下一篇博客会介绍相关的msmq、queue等等,后面精彩继续~~~~~