1. 程式人生 > >AgileEAS.NET SOA 中介軟體平臺.Net Socket通訊框架-介紹

AgileEAS.NET SOA 中介軟體平臺.Net Socket通訊框架-介紹

一、前言

     AgileEAS.NET SOA 中介軟體平臺是一款基於基於敏捷並行開發思想和Microsoft .Net構件(元件)開發技術而構建的一個快速開發應用平臺。用於幫助中小型軟體企業建立一條適合市場快速變化的開發團隊,以達到節省開發成本、縮短開發時間,快速適應市場變化的目的。

     AgileEAS.NET SOA中介軟體平臺提供了敏捷快速開發軟體工程的最佳實踐,通過提供大量的基礎支撐功能如IOC、ORM、SOA、分散式體系及敏捷併發開發方法所支撐的外掛開發體系,以及提供了大量的實體、資料模型設計生成工具、程式碼生成工具,用於幫助中小軟體開發商快速成長。

     AgileEAS.NET平臺充分把握目前軟體行業快速發展的新趨勢,基於敏捷並行開發、快速適應市場這樣淳樸的軟體工程實踐,採用業界廣泛使用的Microsoft .Net構件(元件)開發技術實踐了這種開發思想,幫助軟體企業實現“敏捷變化、快速適合”的目標,從而幫助軟體企業在激烈的市場競爭中贏得先機並獲得更高的回報。

二、關於Socket/Tcp框架的需求

     在AgileEAS.NET SOA 中介軟體平臺在大量客戶的使用過程之中,有的客戶提出了一些基於“訊息推”、和應用系統事件通知的需求,比如在“醫院資訊系統”、“電子病歷系統‘、”區域公共衛生平臺“、等系統之中就提供了這樣的需求,比如當大夫為病人開立了醫囑之後、需要在相關護理人員即時提示,之前大家都使用資料庫重新整理,資料庫的壓力都比較大,所以迫切的提出了這樣的需求。

     另外一個原因是AgileEAS.NET SOA 中介軟體平臺之前一直使用WCF、WS、Romotinig通訊做為SOA分散式架構的通訊基礎,我們在考慮WS、WCF的某些協議並不能提供給我們非常高效的通訊,所以我們也需要有一套直接基於Socket/TCP的通訊體系用於支撐我們的SOA分散式服務業務體系。

三、AgileEAS.NET SOA 中介軟體Socket/Tcp框架結構

     AgileEAS.NET SOA中介軟體需要的Socket/Tcp框架嚴格意思是需要的基於Socket的通訊訊息中件間,其所提供的功能本質是對訊息的處理,所以其所提供的API有三大類、Socket框架本身、訊息框架及訊息處理框架,以下是AgileEAS.NET SOA中介軟體的Socket/Tcp的應用框架結構:

image_thumb2

     各上圖我們可以看到AgileEAS.NET SOA中介軟體需要的Socket/Tcp框架實現了這麼一件有意思的事,把原生的Socekt基於資料流的流式通訊模式轉換為基於訊息的訊息通訊模式,讓開發人員多複雜的系統Socket通訊和資料流處理之中解放出來,轉而關心高層通訊訊息的設計和訊息處理的業務設計與實現。

三、AgileEAS.NET SOA 中介軟體Socket/Tcp框架重要的介面和類

     AgileEAS.NET SOA中介軟體需要的Socket/Tcp框架嚴格意思是需要的基於Socket的通訊訊息中件間,其所提供的功能本質是對訊息的處理,所以其所提供的API有三大類、Socket框架本身、訊息框架及訊息處理框架,以下是AgileEAS.NET SOA中介軟體的Socket/Tcp的應用框架結構:

Sockets_thumb1

     其中ISocketCient介面為客戶段功能封裝,其定義大體如下:

   1: /// <summary>
   2: /// Tcp客戶端介面。
   3: /// </summary>
   4: public interface ISocketClient : ISocketEngine
   5: {
   6:     /// <summary>
   7:     /// 客戶端狀態。
   8:     /// </summary>
   9:     ClientState ClientState
  10:     {
  11:         get;
  12:     }        
  13:  
  14:     /// <summary>
  15:     /// 連線Tcp伺服器。
  16:     /// </summary>
  17:     bool Connect();
  18:  
  19:     /// <summary>
  20:     /// 關閉與伺服器的連線。
  21:     /// </summary>
  22:     void Close();
  23:  
  24:     /// <summary>
  25:     /// 傳送訊息。
  26:     /// </summary>
  27:     /// <param name="message">訊息。</param>
  28:     void Send(IMessage message);
  29:  
  30:     /// <summary>
  31:     /// 呼叫訊息,用於伺服器/客戶端應用中的請示==》響應訊息的應用。
  32:     /// </summary>
  33:     /// <param name="request">請示訊息。</param>
  34:     /// <returns>伺服器返回的響應訊息。</returns>
  35:     IMessage Invoke(IMessage request);
  36:  
  37:     /// <summary>
  38:     /// 非同步呼叫訊息,用於伺服器/客戶端應用中的請示==》響應訊息的應用。
  39:     /// </summary>
  40:     /// <param name="request">請示訊息。</param>
  41:     /// <returns>包含響應訊息的非同步任務。</returns>
  42:     NetInvokeTask BeginInvoke(IMessage request);
  43:  
  44:     /// <summary>
  45:     /// 伺服器發生錯誤時觸發。
  46:     /// </summary>
  47:     event ErrorEventHandler Error;
  48:  
  49:     /// <summary>
  50:     /// 連線伺服器後觸發。
  51:     /// </summary>
  52:     event EventHandler Connected;
  53:  
  54:     /// <summary>
  55:     /// 斷開伺服器連線後觸發。
  56:     /// </summary>
  57:     event EventHandler Closed;
  58: }

     其是最重要方法為void Send(IMessage message)方法,即傳送一個訊息到伺服器,這個方法也是對使用者開放的最重要方法,在這裡傳送的不是位元組流,而是一個實現了IMessage介面的訊息物件,當服戶段接收到IMessage物件之後會呼叫與其對應的訊息處理器(IMessageHandler)物件進行訊息處理,反之客戶段收到IMessage也會呼叫與其相關的訊息處理器(IMessageHandler)物件進行處理。

     ISocketServer、ISocketServerBase介面:

   1: /// <summary>
   2: /// Socket伺服器基類介面。
   3: /// </summary>
   4: public interface ISocketServerBase : ISocketEngine
   5: {
   6:     /// <summary>
   7:     /// 客戶端會話集合。
   8:     /// </summary>
   9:     IList<NetSession> Sessions
  10:     {
  11:         get;
  12:     }
  13:  
  14:     /// <summary>
  15:     /// 註冊了一個新會話後發生。
  16:     /// </summary>
  17:     event NetSessionEventHandler SessionStarted;
  18:  
  19:     /// <summary>
  20:     /// 某一個會話結束後發生。
  21:     /// </summary>
  22:     event NetSessionEventHandler SessionAbandoned;
  23:  
  24:     /// <summary>
  25:     /// 傳送訊息。
  26:     /// </summary>
  27:     /// <param name="target">訊息接收方ID(會話ID)。</param>
  28:     /// <param name="message">訊息。</param>
  29:     void Send(Guid target, IMessage message);
  30:  
  31:     /// <summary>
  32:     /// 傳送網路訊息。
  33:     /// </summary>
  34:     /// <param name="target">訊息接收方ID(會話ID)。</param>
  35:     /// <param name="netMessage">網路訊息。</param>
  36:     void Send(Guid target, NetMessage netMessage);
  37:  
  38:     /// <summary>
  39:     /// 傳送網路報文(僅閘道器模式有效)。
  40:     /// </summary>
  41:     /// <param name="target">訊息接收方ID(會話ID)。</param>
  42:     /// <param name="netPacket">網路報文。</param>
  43:     void Send(Guid target, NetPacket netPacket);
  44:  
  45:     /// <summary>
  46:     /// 傳送網路資料(僅閘道器模式有效)。
  47:     /// </summary>
  48:     /// <param name="target">訊息接收方ID(會話ID)。</param>
  49:     /// <param name="buffer">網路資料。</param>
  50:     void Send(Guid target, byte[] buffer);
  51: }
   1: /// <summary>
   2: /// Socket伺服器介面。
   3: /// </summary>
   4: public interface ISocketServer :  ISocketServerBase
   5: {
   6:     /// <summary>
   7:     /// 客戶端連線數。
   8:     /// </summary>
   9:     int ClientCount
  10:     {
  11:         get;
  12:     }
  13:  
  14:     /// <summary>
  15:     /// 伺服器狀態。
  16:     /// </summary>
  17:     ServerState ServerState
  18:     {
  19:         get;
  20:     }        
  21:  
  22:     /// <summary>
  23:     /// 開始Tcp伺服器。
  24:     /// </summary>
  25:     void StartServer();
  26:  
  27:     /// <summary>
  28:     /// 停止Tcp伺服器。
  29:     /// </summary>
  30:     void StopServer();
  31:  
  32:     /// <summary>
  33:     /// 關閉指定客戶的連線。
  34:     /// </summary>
  35:     /// <param name="client">客戶Guid。</param>
  36:     void AbandonSession(System.Guid client);
  37:  
  38:     /// <summary>
  39:     /// 伺服器發生錯誤時觸發。
  40:     /// </summary>
  41:     event ServerErrorEventHandler ServerError;
  42:  
  43:     /// <summary>
  44:     /// 伺服器啟動後觸發。
  45:     /// </summary>
  46:     event System.EventHandler ServerStarted;        
  47:  
  48:     /// <summary>
  49:     /// 伺服器停止後觸發。
  50:     /// </summary>
  51:     event System.EventHandler ServerStopped;
  52: }

     這兩個介面定義了SocketServer的一些行為和屬性,其中最重要的方法還是void Send(Guid target, IMessage message),實現向某個特定客戶段連線傳送應用訊息,別外定義了一個IList<NetSession> Sessions屬性,表示目前連線到此SocketServer的所有客戶端會話資訊。

     NetSession表示伺服器的一個客戶段連線會話,包括連線上下文資訊和連線的Socket通訊物件,當某個SocketClient傳送給SocketServer的資訊都會被與其應對的NetSession進行處理,NetSession定義兩個重要的方法public void Reply(uint requestID, IMessage message)和public void Abandon(),其中Reply表示向客戶端回覆一個訊息,Abandon表示伺服器強制中止此會話。

     在整個Socket/tcp框架之中進行通訊的最基本單元都是IMessage,那麼SocketClient、SocketServer接收到IMessage如何處理呢,答案是由與之配對的IMessageHandler進行處理,所以SocketClient、SocketServer都實現了一個基礎介面ISocketEngine:

   1: /// <summary>
   2: /// Socket引擎,Socket網路通訊基礎類。
   3: /// </summary>
   4: public interface ISocketEngine : IDisposable
   5: {
   6:     /// <summary>
   7:     /// 通訊引擎的全域性唯一識別符號號。
   8:     /// </summary>
   9:     System.Guid Guid
  10:     {
  11:         get;
  12:     }
  13:  
  14:     /// <summary>
  15:     /// IP地址和埠號。
  16:     /// </summary>
  17:     IPEndPoint IPEndPoint
  18:     {
  19:         get;
  20:         set;
  21:     }
  22:  
  23:     /// <summary>
  24:     /// IP地址。
  25:     /// </summary>
  26:     string IPAddress
  27:     {
  28:         get;
  29:         set;
  30:     }
  31:  
  32:     /// <summary>
  33:     /// 埠號。
  34:     /// </summary>
  35:     int Port
  36:     {
  37:         get;
  38:         set;
  39:     }
  40:  
  41:     /// <summary>
  42:     /// 報文最大長度。
  43:     /// </summary>
  44:     int MessageMaxSize
  45:     {
  46:         get;
  47:     }        
  48:  
  49:     /// <summary>
  50:     /// 註冊訊息處理器。
  51:     /// </summary>
  52:     /// <typeparam name="T">訊息型別。</typeparam>
  53:     /// <param name="hander">訊息處理器。</param>
  54:     void AddHander<T>(IMessageHandler<T> hander) where T : IMessage;
  55:  
  56:     /// <summary>
  57:     /// 通過Socket傳送資料之後觸發。
  58:     /// </summary>
  59:     event SocketDataHandler SocketDataSend;
  60:  
  61:     /// <summary>
  62:     ///  通過Socket接收資料之後觸發。
  63:     /// </summary>
  64:     event SocketDataHandler SocketDataReceived;
  65:  
  66:     /// <summary>
  67:     /// 傳送報文完成之後觸發。
  68:     /// </summary>
  69:     event PacketHandler PacketSend;
  70:  
  71:     /// <summary>
  72:     /// 報文接收完成之後觸發。
  73:     /// </summary>
  74:     event PacketHandler PacketReceived;
  75:  
  76:     /// <summary>
  77:     /// 載送完一個NetMessage之後觸發。
  78:     /// </summary>
  79:     event NetMessageHandler NetMessageSend;
  80:  
  81:     /// <summary>
  82:     /// 接收完一個NetMessage之後觸發。
  83:     /// </summary>
  84:     event NetMessageHandler NetMessageReceived;
  85:  
  86:     /// <summary>
  87:     /// 訊息傳送完成之後觸發。
  88:     /// </summary>
  89:     event MessageHandler MessageSend;
  90:  
  91:     /// <summary>
  92:     /// 接收訊息完成之後觸發。
  93:     /// </summary>
  94:     event MessageHandler MessageReceived;
  95: }

     其中方法void AddHander<T>(IMessageHandler<T> hander) where T : IMessage實現對訊息處理器的註冊,以便收到IMessage之後選擇合適的處理器進行處理。

四、訊息和訊息處理器

     從以上的介紹我們可以明確的知道AgileEAS.NET SOA中介軟體Socket/Tcp框架是的一個基於訊息物件的訊息通訊框架,那麼其最核心的業務就是定義訊息及訊息的處理思路,我們稱之為訊息及訊息處理器結構:

Message_thumb3

     其中IMessage介面為Socket/Tcp框架中最重要的介面,所有高層的應用訊息都需要實現本介面:

   1: /// <summary>
   2: /// 訊息介面定義。
   3: /// </summary>
   4: /// <remarks>
   5: /// 這裡所說的訊息是指業務處理的最小單元,而不是傳輸於網路之間的網路訊息。
   6: /// </remarks>
   7: public interface IMessage
   8: {
   9:     /// <summary>
  10:     /// 從指定的 MessageReader載入訊息物件。
  11:     /// </summary>
  12:     /// <param name="reader">訊息讀取器。</param>
  13:     void Load(BufferReader reader);
  14:  
  15:     /// <summary>
  16:     /// 將訊息物件儲存到指定的MessageWriter。
  17:     /// </summary>
  18:     /// <param name="writer">訊息編寫器。</param>
  19:     void WriteTo(BufferWriter writer);
  20: }

     其中Load和WriteTo實現IMessage訊息物件例項與位元組流之間進行相互轉換,Load訊息用於從位元組流之中讀取並例項化訊息、WriteTo把訊息轉換為流寫入訊息流之中,在應用開發過程之中必須實現這兩個方法並且在訊息類上打上MessageAttribute標記:

   1: /// <summary>
   2: /// 訊息ID屬性。
   3: /// </summary>
   4: /// <remarks>
   5: /// 標記網路訊息,確定其唯一的ID。
   6: /// </remarks>
   7: [AttributeUsage(AttributeTargets.Class)]
   8: public class MessageAttribute : Attribute
   9: {
  10:     /// <summary>
  11:     /// 初始化MessageAttribute物件例項。
  12:     /// </summary>
  13:     /// <param name="messageID">訊息ID。</param>
  14:     public MessageAttribute(string messageID)
  15:         :this(messageID,string.Empty)
  16:     {
  17:  
  18:     }
  19:  
  20:     /// <summary>
  21:     /// 初始化MessageAttribute物件例項。
  22:     /// </summary>
  23:     /// <param name="messageID">訊息ID。</param>
  24:     /// <param name="description">訊息說明。</param>
  25:     public MessageAttribute(string messageID, string description)
  26:     {
  27:         this.MessageID = new Guid(messageID);
  28:         this.Description = description;
  29:     }
  30:  
  31:     /// <summary>
  32:     /// 訊息ID。
  33:     /// </summary>
  34:     public Guid MessageID
  35:     {
  36:         get;
  37:         set;
  38:     }
  39:  
  40:     /// <summary>
  41:     /// 訊息說明。
  42:     /// </summary>
  43:     public string Description
  44:     {
  45:         get;
  46:         set;
  47:     }
  48: }

     MessageAttribute標記用於向已實現IMessage介面的具體訊息的訊息ID與訊息說明,即向Socket通訊框架聲音本訊息的唯一性之用,其中MessageID為一個GUID物件,GUID物件理論上是唯一的,我們可以表示訊息的唯一性,以下是一個具體的訊息例子:

   1: /// <summary>
   2: /// 使用者登入訊息。
   3: /// </summary>
   4: [Message("F42433DF-2D4D-4514-9523-2FE911E63CAA", "登入訊息")]
   5: [Serializable]
   6: public class LoginMessage : IMessage
   7: {
   8:     /// <summary>
   9:     /// 使用者名稱。
  10:     /// </summary>
  11:     public string LoginID
  12:     {
  13:         get;
  14:         set;
  15:     }
  16:  
  17:     /// <summary>
  18:     /// 密碼。
  19:     /// </summary>
  20:     public string PassWord
  21:     {
  22:         get;
  23:         set;
  24:     }
  25:  
  26:     #region IMessage 成員
  27:  
  28:     /// <summary>
  29:     /// 
  30:     /// </summary>
  31:     /// <param name="reader"></param>
  32:     public void Load(EAS.IO.BufferReader reader)
  33:     {
  34:         LoginID = reader.ReadString();
  35:         PassWord = reader.ReadString();
  36:     }
  37:  
  38:     /// <summary>
  39:     /// 
  40:     /// </summary>
  41:     /// <param name="writer"></param>
  42:     public void WriteTo(EAS.IO.BufferWriter writer)
  43:     {
  44:         writer.Write(LoginID);
  45:         writer.Write(PassWord);
  46:     }
  47:  
  48:     #endregion
  49: }

     以上是一個具體訊息的例子,其表明訊息ID為“F42433DF-2D4D-4514-9523-2FE911E63CAA”,其作用是登入訊息,用於實現類似登入業務。

五、可靠的訊息中介軟體

     AgileEAS.NET SOA中介軟體Socket/Tcp框架是一個可靠的訊息中介軟體,在設計過程之初就選擇了完成埠模型進行開發,以保證服務的高併發和吞吐量,在底層訊息通訊上,我們選擇了不超過8K的可變大小通訊報文,比如當一個高層的IMeesage只有512位元組內容的時候,會取轉成一個一個遠小於8K的報文進行傳送,如果一個高層IMeesage為66K時,會被分解成為9條訊息報文進行通訊,前8條訊息報文長度為8K,最後一條不滿足8K,接收文收到這9條報文後組合並轉換為IMeesage物件之後交由訊息處理器IMeeesgaHandler進行處理。

     在進行訊息報文收發過程之中,經過長期測試、驗證、設計和選擇了高效能的防粘包設計,避免應用開發者頭疼的訊息粘包問題。

六、AgileEAS.NET SOA中介軟體需要的Socket/Tcp框架下載

     AgileEAS.NET SOA中介軟體Socket/Tcp框架包含在AgileEAS.NET SOA中介軟體平臺之中,具體定義在EAS.MicroKernel.dll程式集之中,要使用AgileEAS.NET SOA中介軟體Socket/Tcp框架進行基於Socket的通訊開發,請通過AgilleEAS.NET SOA 中站件平臺官方網站最新下載頁面下載。

七、聯絡我們

     為了完善、改進和推廣AgileEAS.NET而成立了敏捷軟體工程實驗室,是一家研究、推廣和發展新技術,並致力於提供具有自主智慧財產權的業務基礎平臺軟體,以及基於業務基礎平臺了開發的管理軟體的專業軟體提供商。主要業務是為客戶提供軟體企業研發管理解決方案、企業管理軟體開發,以及相關的技術支援,管理及技術諮詢與培訓業務。

     AgileEAS.NET平臺自2004年秋呱呱落地一來,我就一直在逐步完善和改進,也被應用於保險、醫療、電子商務、房地產、鐵路、教育等多個應用,但一直都是以我個人在推廣,2010年因為我辭職休息,我就想到把AgileEAS.NET推向市場,讓更多的人使用。

     我的技術團隊成員都是合作多年的老朋友,因為這個平臺是免費的,所以也沒有什麼收入,都是由程式設計師的那種理想與信念堅持,在此我感謝一起奮鬥的朋友。

QQ:47920381,AgileEAS.NET

QQ群:113723486(AgileEAS SOA 平臺)/上限1000人

199463175(AgileEAS SOA 交流)/上限1000人

120661978(AgileEAS.NET 平臺交流)/上限1000人

212867943(AgileEAS.NET研究)/上限500人

147168308(AgileEAS.NET應用)/上限500人

172060626(深度AgileEAS.NET平臺)/上限500人

116773358(AgileEAS.NET 平臺)/上限500人

125643764(AgileEAS.NET探討)/上限500人

193486983(AgileEAS.NET 平臺)/上限500人

郵件:[email protected],[email protected],

電話:18629261335。