龐銳 呂達 陳科
摘要: 針對現代軟件系統中模塊協同工作的通信需求,提出了一個軟件通信框架的完整實現方案。通過分析軟件系統中對模塊通信的要求,建立統一的事件模型,完成進程間、進程內通信框架設計,并利用Qt開發庫完成通信框架的軟件實現。使用該軟件通信框架可以減少模塊通信復雜度,縮短軟件通信功能開發周期,提高軟件可維護性,而且利于擴展和移植。
關鍵詞: 模塊通信; 事件模型; 軟件框架; 面向對象; Qt
中圖分類號:TP391文獻標志碼:A 文章編號:1006-8228(2012)11-16-03
Design and implementation of software communication framework based on uniform event model
Pang Rui, Lv Da, Chen Ke
(SINOPEC Geophysical Research Institute, Nanjing, Jiangsu 211103, China)
Abstract: Targeted on module communication requirement of modern software system, a solution to software communication framework is proposed. By analyzing communication requirement in module development, uniform event model is constructed, and software framework for module communication is designed. Finally, by using Qt, a communication framework is realized. Using the framework can reduce module complicacy and shorten development period of communication. Furthermore, software maintenance is improved, and software transplant benefits.
Key words: module communication; event model; software framework; object-oriented; Qt
0 引言
隨著計算機技術的飛速發展,各類軟件系統為了滿足不斷變化的用戶需求,提供的功能越來越多,其軟件規模日益龐大,實現復雜度也越來越高。在現代軟件系統中,對復雜的業務需要進行層次劃分,將業務功能相對模塊化,模塊具備高內聚低耦合的特性,通過模塊間的協同工作來提供復雜的軟件功能[1]。軟件模塊協同工作的基礎是在模塊間可以傳遞信息數據,根據業務劃分不同,可以在一個進程中只包含一個模塊,通過進程間模塊通信協同工作,也可以在一個進程中包含多個模塊,通過進程內模塊通信協同工作。那么,建立一個高效統一的進程間、進程內事件通信機制,才能保證各個模塊間可靠的協作關系,降低軟件系統通信復雜度,提高開發效率。
1 軟件模塊的通信需求分析
面向不同的行業應用領域,軟件模塊的通信需求是不同的。在專家決策系統中,模塊間需要借助通信對同一數據進行聯動操作分析;在游戲軟件中,模塊間需要利用通信對用戶交互操作進行協同處理;在計費軟件中,模塊間需要傳遞各種費用數據。各類軟件系統,其共同點是,需要在模塊間傳遞特定的事件通知或數據信息,以協同完成工作。根據不同軟件系統的設計,軟件模塊的通信可以分類為進程間通信和進程內通信。
⑴ 進程間通信
軟件模塊分散在不同的進程中,模塊需要通過進程間的通信手段來傳遞事件通知和數據信息。通常操作系統提供的進程間通信(IPC)方式主要有:信號、信號量、消息隊列、管道、共享內存、套接字等。其中,信號、信號量、消息隊列可以用于傳遞事件通知,管道、共享內存可以用于傳遞數據信息,套接字的應用更為靈活,可以同時用于事件和數據的傳遞[2]。此外,在Windows操作系統中,還可以利用窗口消息來傳遞事件。雖然操作系統提供了多種進程間通信手段,但是大都與操作系統底層接口緊密相關,如果直接使用,在兼容性和跨平臺方面有所不足。
⑵ 進程內通信
軟件模塊集中在一個進程中,模塊通過進程內的通信手段來傳遞事件通知和數據信息。有別于進程間通信中各個模塊受進程空間隔離,在同一進程內的模塊可以共享進程的內存數據,可以相互調用模塊接口。因此,進程內通信方式比較靈活,可以引用模塊的指針來訪問模塊,也可以向模塊發消息。考慮到軟件開發的規范,需要對進程內通信形式進行統一約定。
2 軟件通信框架設計
2.1 統一的事件模型設計
軟件通信的主要任務就是在模塊間傳遞數據。其首要問題是如何對要傳遞的數據進行規范描述,我們必須建立一個適用于進程內,同時也適用于進程間傳遞的統一事件模型。這個事件模型并不是具體傳遞的事件數據,它是一個規范標準,一個模板,所有參與通信的模塊必須圍繞這個事件模型,定義自己需要接收或發送的具體事件,最終模塊間傳遞的是這些已定義的事件,雖然它們代表的信息各不相同,但都是基于同一個事件模型,有著相同的規范描述。圖1描述了進程間和進程內事件傳遞的模型結構。
圖1事件模型結構圖
一個事件模型需要包含如下基本信息。
事件標識ID:一個整數,表明這個事件的含義;
發送模塊標識ID:一個整數,標識是從哪個模塊發送的事件;
接受模塊標識ID:一個整數,標識事件應由哪個模塊接收;
事件攜帶的信息:一個有限長度的數據緩沖,可以攜帶和事件標識ID相關的附加信息。
軟件模塊開發人員以事件模型為基礎,定義模塊間需要傳遞的具體事件,每個事件包括特定的事件標識。
ID:需要攜帶的信息及信息在數據緩沖中的存放方式。當需要發送事件時,構造一個事件對象,設置發送模塊ID和接收模塊ID,再利用通信框架提供的發送接口把事件發送出去,由通信框架將事件傳遞到接收模塊中。
2.2 基于事件模型的通信框架設計
事件模型是對要傳遞數據的規范描述,那么使用什么載體和機制來傳遞事件則是軟件通信的另一個重要部分。圍繞事件模型,我們需要建立軟件通信框架,為事件在模塊間的傳遞提供基礎支撐。軟件通信框架是一組通用組件以及使用規約的集合,它定義了最基本的事件傳遞流程,并提供相關調用接口,軟件模塊要依據通信框架的使用規約,進行具體的事件發送和接收工作。按照事件傳遞的途徑不同,可以分為進程間通信和進程內通信兩種框架,它們之間有相通之處,但是在事件載體方面有所區別。
⑴ 進程間通信框架
當各個模塊存在于獨立的進程中時,需要在進程間傳遞事件。進程間通信框架采用服務器/客戶端模式:首先存在一個通信服務進程,各個模塊進程啟動后,向通信服務進程注冊自己;然后,各個模塊進程向通信服務進程發送自己的事件,由通信服務根據事件的接收者再把事件轉發到對應的接收模塊上;最后,當模塊進程退出時,要向通信服務注銷自己。進程間通信框架結構如圖2所示。
[通信組件][通信服務進程] [通信組件] [通信組件][發送事件模塊(進程A)][接收事件模塊(進程B)] [event] [操作系統
底層載體][event]
圖2進程間通信框架結構圖
此外,考慮到通信框架的通用性,設計了通用的進程間通信組件。模塊進程和服務進程都通過通信組件來傳遞事件,由通信組件選擇合適的操作系統的底層功能作為事件的載體,進行傳送,這樣可以在通信框架層次上隱藏底層細節。
⑵ 進程內通信框架
當各個模塊存在于同一個進程中時,需要在進程內傳遞事件。進程內通信框架和進程間框架類似,也是采用服務/客戶端模式,其特別之處是服務端和客戶端都在一個進程內部。同時,利用進程內可以共享數據的特點,省略了通信組件這個層次,各個模塊直接向通信服務對象注冊自己,并直接向通信服務對象發送事件,再由其將事件轉發到相關接收模塊。這樣既保持了進程間和進程內通信框架的結構統一性,又提高了進程內的通信效率。進程內通信框架結構如圖3所示。
[通信服務對象(進程內)][發送事件模塊(進程內)][接收事件模塊(進程內)][event][event]
圖3進程內通信框架結構圖
3 軟件通信框架實現
基于上述軟件通信框架的設計,使用面向對象的開發方法(C++編程語言),在Qt開發庫的基礎上進行軟件通信框架的開發實現。面向對象開發方法以對象為基礎,利用特定的軟件工具直接完成從對象客體的描述到軟件結構之間的轉換,解決了傳統結構化開發方法中客觀世界描述工具與軟件結構的不一致性問題,縮短了開發周期,解決了從分析和設計到軟件模塊結構之間多次轉換映射的繁雜過程,是一種很有發展前途的系統開發方法[3]。Qt是一個先進的,面向對象的,跨平臺的圖形開發庫,其主要優點是: 優良的跨平臺特性,支持Windows、Linux操作系統;面向對象特性,良好封裝機制使得Qt的模塊化程度非常高,可重用性較好,對于用戶開發來說是非常方便的;豐富的API,包括多達250個以上的具有強大功能的C++類[4]。
3.1 事件模型實現
Qt本身包含一套事件模型,我們根據自己事件模型的設計,在Qt事件的基礎上,利用面向對象的派生特性[5],進行擴展,形成事件模型NewsEvent,整個通信框架都使用NewsEvent進行通信,主要實現代碼如下:
#define NEInvalid -1 //無效事件ID
//模塊的identify_key,也作為_senderId or_recverId:
#define NewsMain_ID0
#define Area_ID 1
#define Seis_ID2
class NewsEvent:public QEvent //在QEvent基礎上進行擴展
{//下邊是進程間需要傳遞的核心數據,一共132個字節
(32位系統)
long_senderId; //發送模塊的identify_key
int_recverId; //接收模塊的identify_key,發給所有帶這個識別
key的模塊
int_eventId; //事件ID:普通事件ID必須>0,<=0的事件ID用作
特殊系統管理
union EventData//事件攜帶的信息,可以根據事件id約定如何
使用其中的相關數據項
{char charValue[120];
short shortValue[60];
int intValue[30];
float floatValue[30];
double doubleValue[15];
}_eventData;
};
在事件ID的定義方面,提供了統一的事件ID定義函數,可以對不同模塊的事件ID進行管理,避免不同模塊間事件ID的沖突。
//NEMAKER是事件ID生成器:用模塊標志頭組合內部ID,
生成惟一的事件ID
#define NEMAKER(frame,id) NEMAKER_p(frame,id)
#define NEMAKER_p(frame,id) frame##id
/****各類模塊事件標志頭****/
#define NENewsMain 10
#define NEArea 11
#define NESeis 12
//###系統管理###
#define NEClientRegister -998 //client向通信服務進程注冊自己
#define NEClientUnregister -999 //client向通信服務進程注銷自己
//###剖面模塊###
#define NEMousePositionInSection NEMAKER(NESeis,0)
//鼠標在剖面上的位置
#define NEInterpretDataChangeInSection NEMAKER(NESeis,1)
//剖面上解釋數據變動
各個模塊根據自己的需求,定義自己的事件ID,并約定好事件所攜帶的信息,以NewsEvent對象的形式通過框架接口將事件發送出去,接收時,通過框架接口接收NewsEvent對象,并進行處理。
3.2 通信框架實現
基于Qt的事件傳遞機制,開發軟件通信框架。因為Qt提供了完善的對象間(同一進程內)傳遞事件的機制,通信框架可以把軟件模塊作為對象,利用Qt進行事件傳遞。我們的主要工作是實現發送/接收事件的標準接口,進程間通信組件,進程間通信服務程序及進程內通信服務對象。
⑴ 發送/接收事件標準接口
void SendNewsEvent(QObject* target,NewsEvent* event); //發送事件
virtual void ProcessNewsEvent(NewsEvent* event); //接收事件
所有需要發送事件的模塊都使用SendNewsEvent發送事件,所有需要接收事件的模塊都重新實現ProcessNewsEvent虛函數,進行事件處理。在進程間通信中,SendNewsEvent函數中的target是模塊自己的通信組件,由通信組件將事件發送給通信服務程序。在進程內通信中,target是進程內惟一的通信服務對象。
⑵ 進程間通信組件
進程間通信組件用于進程間通信框架,它是模塊與通信服務程序的連接橋梁,模塊通過通信組件向通信服務程序注冊自己,發送事件,接收事件,通信服務程序通過通信組件向模塊轉發事件。考慮到跨平臺的兼容性,通信組件使用套接字(Socket)作為事件的載體,在模塊和通信服務程序間傳遞數據。
在進程間通信中,模塊并不是直接將NewsEvent發送給通信服務程序,而是發送給進程間通信組件,由其將事件發送到通信服務程序,同樣,通信服務程序發來的事件也是由通信組件接收,再發送給目標模塊。
void ClientRegister(); //模塊調用其向通信服務程序進行注冊
void ClientUnregister(); //模塊調用其向通信服務程序進行注銷
void TransNewsEvent(NewsEvent* event,QHostAddress &ip,
quint16 port); //發送事件到服務程序
void ReceiveNewsEvent(NewsEvent* event); //從服務程序接收事件
⑶ 通信服務程序/通信服務對象
通信服務程序和通信服務對象的主要功能相同,都是管理模塊的注冊與注銷,并負責把發送給它的事件轉發到已注冊的相關模塊中。區別在于通信服務程序管理進程間的模塊通信,而通信服務對象管理進程內的模塊通信。
void RegisterModule(); //模塊注冊
void UnregisterModule(); //模塊注銷
void DispatchNewsEvent(NewsEvent* event); //轉發模塊事件
事件在進程間和進程內傳遞方式的區別由通信框架進行封裝,對模塊而言,它面向的是統一的軟件通信框架,只需要按照框架規范開發,就可以進行通信。
4 結束語
本文描述了一種軟件通信框架的設計過程,并給出了一個較為簡單的通信框架實現。它基于面向對象的設計方法,使用C++編程語言,利用Qt開發庫來進行實現。使用基于統一事件模型的軟件通信框架可以減少模塊通信復雜度,縮短軟件通信功能開發周期,提高軟件可維護性,而且利于擴展和移植。然而面對軟件系統中繁多的通信需求,目前還無法在本框架內考慮周全,只有在不斷迭代細化框架的過程中,才能使問題逐一明了。目前,此軟件通信框架已在“NEWS油氣勘探綜合解釋系統”中得到應用,能完全滿足解釋系統需求,應用效果較好。
參考文獻:
[1] 王宏琳.地球物理軟件體系結構研究[J].石油地球物理勘探,2008.43
(5):606-611
[2] 李卓桓.Linux網絡編程[M].機械工業出版社,2000.
[3] C.Thomas Wu.面向對象程序設計導論[M].電子工業出版社,2000.
[4] Xteam軟件技術有限公司.Qt程序設計[M].清華大學出版社,2002.
[5] 錢能.C++程序設計教程[M].清華大學出版社,1999.