很久都沒有寫博客了,從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等等,后面精彩繼續~~~~~