一、前言
AgileEAS.NET SOA 中間件平台是一款基于基于靈活并行開發思想和Microsoft .Net構件(元件)開發技術而建構的一個快速開發應用平台。用于幫助中小型軟體企業建立一條适合市場快速變化的開發團隊,以達到節省開發成本、縮短開發時間,快速适應市場變化的目的。
AgileEAS.NET SOA中間件平台提供了靈活快速開發軟體工程的最佳實踐,通過提供大量的基礎支撐功能如IOC、ORM、SOA、分布式體系及靈活并發開發方法所支撐的插件開發體系,以及提供了大量的實體、資料模型設計生成工具、代碼生成工具,用于幫助中小軟體開發商快速成長。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuQVRO5yUBVUZsl2ZB9CXlRWYqR3chV2Lc12bj91cn9Gbi52YvwVbvNmLzd2bsJmbj5ycldWYtl2Lc9CX6MHc0RHaiojIsJye.png)
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的應用架構結構:
各上圖我們可以看到AgileEAS.NET SOA中間件需要的Socket/Tcp架構實作了這麼一件有意思的事,把原生的Socekt基于資料流的流式通信模式轉換為基于消息的消息通信模式,讓開發人員多複雜的系統Socket通信和資料流處理之中解放出來,轉而關心高層通信消息的設計和消息處理的業務設計與實作。
三、AgileEAS.NET SOA 中間件Socket/Tcp架構重要的接口和類
其中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架構是的一個基于消息對象的消息通信架構,那麼其最核心的業務就是定義消息及消息的處理思路,我們稱之為消息及消息處理器結構:
其中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推向市場,讓更多的人使用。
我的技術團隊成員都是合作多年的老朋友,因為這個平台是免費的,是以也沒有什麼收入,都是由程式員的那種理想與信念堅持,在此我感謝一起奮鬥的朋友。
團隊網站:http://www.agilelab.cn
AgileEAS.NET網站:http://www.agileeas.net
官方部落格:http://eastjade.cnblogs.com
github:https://github.com/agilelab/eas
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。
作者:魏瓊東
出處:http://www.cnblogs.com/eastjade
關于作者:有13年的軟體從業經曆,專注于中小軟體企業軟體開發過程研究,通過在技術與管理幫助中小軟體企業實作技術層面開源節流的目的。熟悉需求分析、企業架構、項目管理。現主要從事基于AgileEAS.NET平台的技術咨詢工作,主要服務于醫療衛生、鐵路、電信、物流、物聯網、制造、零售等行業。如有問題或建議,請多多賜教!
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,如有問題,可以通過[email protected] 聯系我,也可以加入QQ群:113723486、199463175、116773358、116773358、212867943、147168308、59827496、193486983、15118502和大家共同讨論,非常感謝。