龐銳 呂達(dá) 陳科
摘要: 針對(duì)現(xiàn)代軟件系統(tǒng)中模塊協(xié)同工作的通信需求,提出了一個(gè)軟件通信框架的完整實(shí)現(xiàn)方案。通過分析軟件系統(tǒng)中對(duì)模塊通信的要求,建立統(tǒng)一的事件模型,完成進(jìn)程間、進(jìn)程內(nèi)通信框架設(shè)計(jì),并利用Qt開發(fā)庫(kù)完成通信框架的軟件實(shí)現(xiàn)。使用該軟件通信框架可以減少模塊通信復(fù)雜度,縮短軟件通信功能開發(fā)周期,提高軟件可維護(hù)性,而且利于擴(kuò)展和移植。
關(guān)鍵詞: 模塊通信; 事件模型; 軟件框架; 面向?qū)ο螅?Qt
中圖分類號(hào):TP391文獻(xiàn)標(biāo)志碼:A 文章編號(hào):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 引言
隨著計(jì)算機(jī)技術(shù)的飛速發(fā)展,各類軟件系統(tǒng)為了滿足不斷變化的用戶需求,提供的功能越來越多,其軟件規(guī)模日益龐大,實(shí)現(xiàn)復(fù)雜度也越來越高。在現(xiàn)代軟件系統(tǒng)中,對(duì)復(fù)雜的業(yè)務(wù)需要進(jìn)行層次劃分,將業(yè)務(wù)功能相對(duì)模塊化,模塊具備高內(nèi)聚低耦合的特性,通過模塊間的協(xié)同工作來提供復(fù)雜的軟件功能[1]。軟件模塊協(xié)同工作的基礎(chǔ)是在模塊間可以傳遞信息數(shù)據(jù),根據(jù)業(yè)務(wù)劃分不同,可以在一個(gè)進(jìn)程中只包含一個(gè)模塊,通過進(jìn)程間模塊通信協(xié)同工作,也可以在一個(gè)進(jìn)程中包含多個(gè)模塊,通過進(jìn)程內(nèi)模塊通信協(xié)同工作。那么,建立一個(gè)高效統(tǒng)一的進(jìn)程間、進(jìn)程內(nèi)事件通信機(jī)制,才能保證各個(gè)模塊間可靠的協(xié)作關(guān)系,降低軟件系統(tǒng)通信復(fù)雜度,提高開發(fā)效率。
1 軟件模塊的通信需求分析
面向不同的行業(yè)應(yīng)用領(lǐng)域,軟件模塊的通信需求是不同的。在專家決策系統(tǒng)中,模塊間需要借助通信對(duì)同一數(shù)據(jù)進(jìn)行聯(lián)動(dòng)操作分析;在游戲軟件中,模塊間需要利用通信對(duì)用戶交互操作進(jìn)行協(xié)同處理;在計(jì)費(fèi)軟件中,模塊間需要傳遞各種費(fèi)用數(shù)據(jù)。各類軟件系統(tǒng),其共同點(diǎn)是,需要在模塊間傳遞特定的事件通知或數(shù)據(jù)信息,以協(xié)同完成工作。根據(jù)不同軟件系統(tǒng)的設(shè)計(jì),軟件模塊的通信可以分類為進(jìn)程間通信和進(jìn)程內(nèi)通信。
⑴ 進(jìn)程間通信
軟件模塊分散在不同的進(jìn)程中,模塊需要通過進(jìn)程間的通信手段來傳遞事件通知和數(shù)據(jù)信息。通常操作系統(tǒng)提供的進(jìn)程間通信(IPC)方式主要有:信號(hào)、信號(hào)量、消息隊(duì)列、管道、共享內(nèi)存、套接字等。其中,信號(hào)、信號(hào)量、消息隊(duì)列可以用于傳遞事件通知,管道、共享內(nèi)存可以用于傳遞數(shù)據(jù)信息,套接字的應(yīng)用更為靈活,可以同時(shí)用于事件和數(shù)據(jù)的傳遞[2]。此外,在Windows操作系統(tǒng)中,還可以利用窗口消息來傳遞事件。雖然操作系統(tǒng)提供了多種進(jìn)程間通信手段,但是大都與操作系統(tǒng)底層接口緊密相關(guān),如果直接使用,在兼容性和跨平臺(tái)方面有所不足。
⑵ 進(jìn)程內(nèi)通信
軟件模塊集中在一個(gè)進(jìn)程中,模塊通過進(jìn)程內(nèi)的通信手段來傳遞事件通知和數(shù)據(jù)信息。有別于進(jìn)程間通信中各個(gè)模塊受進(jìn)程空間隔離,在同一進(jìn)程內(nèi)的模塊可以共享進(jìn)程的內(nèi)存數(shù)據(jù),可以相互調(diào)用模塊接口。因此,進(jìn)程內(nèi)通信方式比較靈活,可以引用模塊的指針來訪問模塊,也可以向模塊發(fā)消息??紤]到軟件開發(fā)的規(guī)范,需要對(duì)進(jìn)程內(nèi)通信形式進(jìn)行統(tǒng)一約定。
2 軟件通信框架設(shè)計(jì)
2.1 統(tǒng)一的事件模型設(shè)計(jì)
軟件通信的主要任務(wù)就是在模塊間傳遞數(shù)據(jù)。其首要問題是如何對(duì)要傳遞的數(shù)據(jù)進(jìn)行規(guī)范描述,我們必須建立一個(gè)適用于進(jìn)程內(nèi),同時(shí)也適用于進(jìn)程間傳遞的統(tǒng)一事件模型。這個(gè)事件模型并不是具體傳遞的事件數(shù)據(jù),它是一個(gè)規(guī)范標(biāo)準(zhǔn),一個(gè)模板,所有參與通信的模塊必須圍繞這個(gè)事件模型,定義自己需要接收或發(fā)送的具體事件,最終模塊間傳遞的是這些已定義的事件,雖然它們代表的信息各不相同,但都是基于同一個(gè)事件模型,有著相同的規(guī)范描述。圖1描述了進(jìn)程間和進(jìn)程內(nèi)事件傳遞的模型結(jié)構(gòu)。
圖1事件模型結(jié)構(gòu)圖
一個(gè)事件模型需要包含如下基本信息。
事件標(biāo)識(shí)ID:一個(gè)整數(shù),表明這個(gè)事件的含義;
發(fā)送模塊標(biāo)識(shí)ID:一個(gè)整數(shù),標(biāo)識(shí)是從哪個(gè)模塊發(fā)送的事件;
接受模塊標(biāo)識(shí)ID:一個(gè)整數(shù),標(biāo)識(shí)事件應(yīng)由哪個(gè)模塊接收;
事件攜帶的信息:一個(gè)有限長(zhǎng)度的數(shù)據(jù)緩沖,可以攜帶和事件標(biāo)識(shí)ID相關(guān)的附加信息。
軟件模塊開發(fā)人員以事件模型為基礎(chǔ),定義模塊間需要傳遞的具體事件,每個(gè)事件包括特定的事件標(biāo)識(shí)。
ID:需要攜帶的信息及信息在數(shù)據(jù)緩沖中的存放方式。當(dāng)需要發(fā)送事件時(shí),構(gòu)造一個(gè)事件對(duì)象,設(shè)置發(fā)送模塊ID和接收模塊ID,再利用通信框架提供的發(fā)送接口把事件發(fā)送出去,由通信框架將事件傳遞到接收模塊中。
2.2 基于事件模型的通信框架設(shè)計(jì)
事件模型是對(duì)要傳遞數(shù)據(jù)的規(guī)范描述,那么使用什么載體和機(jī)制來傳遞事件則是軟件通信的另一個(gè)重要部分。圍繞事件模型,我們需要建立軟件通信框架,為事件在模塊間的傳遞提供基礎(chǔ)支撐。軟件通信框架是一組通用組件以及使用規(guī)約的集合,它定義了最基本的事件傳遞流程,并提供相關(guān)調(diào)用接口,軟件模塊要依據(jù)通信框架的使用規(guī)約,進(jìn)行具體的事件發(fā)送和接收工作。按照事件傳遞的途徑不同,可以分為進(jìn)程間通信和進(jìn)程內(nèi)通信兩種框架,它們之間有相通之處,但是在事件載體方面有所區(qū)別。
⑴ 進(jìn)程間通信框架
當(dāng)各個(gè)模塊存在于獨(dú)立的進(jìn)程中時(shí),需要在進(jìn)程間傳遞事件。進(jìn)程間通信框架采用服務(wù)器/客戶端模式:首先存在一個(gè)通信服務(wù)進(jìn)程,各個(gè)模塊進(jìn)程啟動(dòng)后,向通信服務(wù)進(jìn)程注冊(cè)自己;然后,各個(gè)模塊進(jìn)程向通信服務(wù)進(jìn)程發(fā)送自己的事件,由通信服務(wù)根據(jù)事件的接收者再把事件轉(zhuǎn)發(fā)到對(duì)應(yīng)的接收模塊上;最后,當(dāng)模塊進(jìn)程退出時(shí),要向通信服務(wù)注銷自己。進(jìn)程間通信框架結(jié)構(gòu)如圖2所示。
[通信組件][通信服務(wù)進(jìn)程] [通信組件] [通信組件][發(fā)送事件模塊(進(jìn)程A)][接收事件模塊(進(jìn)程B)] [event] [操作系統(tǒng)
底層載體][event]
圖2進(jìn)程間通信框架結(jié)構(gòu)圖
此外,考慮到通信框架的通用性,設(shè)計(jì)了通用的進(jìn)程間通信組件。模塊進(jìn)程和服務(wù)進(jìn)程都通過通信組件來傳遞事件,由通信組件選擇合適的操作系統(tǒng)的底層功能作為事件的載體,進(jìn)行傳送,這樣可以在通信框架層次上隱藏底層細(xì)節(jié)。
⑵ 進(jìn)程內(nèi)通信框架
當(dāng)各個(gè)模塊存在于同一個(gè)進(jìn)程中時(shí),需要在進(jìn)程內(nèi)傳遞事件。進(jìn)程內(nèi)通信框架和進(jìn)程間框架類似,也是采用服務(wù)/客戶端模式,其特別之處是服務(wù)端和客戶端都在一個(gè)進(jìn)程內(nèi)部。同時(shí),利用進(jìn)程內(nèi)可以共享數(shù)據(jù)的特點(diǎn),省略了通信組件這個(gè)層次,各個(gè)模塊直接向通信服務(wù)對(duì)象注冊(cè)自己,并直接向通信服務(wù)對(duì)象發(fā)送事件,再由其將事件轉(zhuǎn)發(fā)到相關(guān)接收模塊。這樣既保持了進(jìn)程間和進(jìn)程內(nèi)通信框架的結(jié)構(gòu)統(tǒng)一性,又提高了進(jìn)程內(nèi)的通信效率。進(jìn)程內(nèi)通信框架結(jié)構(gòu)如圖3所示。
[通信服務(wù)對(duì)象(進(jìn)程內(nèi))][發(fā)送事件模塊(進(jìn)程內(nèi))][接收事件模塊(進(jìn)程內(nèi))][event][event]
圖3進(jìn)程內(nèi)通信框架結(jié)構(gòu)圖
3 軟件通信框架實(shí)現(xiàn)
基于上述軟件通信框架的設(shè)計(jì),使用面向?qū)ο蟮拈_發(fā)方法(C++編程語言),在Qt開發(fā)庫(kù)的基礎(chǔ)上進(jìn)行軟件通信框架的開發(fā)實(shí)現(xiàn)。面向?qū)ο箝_發(fā)方法以對(duì)象為基礎(chǔ),利用特定的軟件工具直接完成從對(duì)象客體的描述到軟件結(jié)構(gòu)之間的轉(zhuǎn)換,解決了傳統(tǒng)結(jié)構(gòu)化開發(fā)方法中客觀世界描述工具與軟件結(jié)構(gòu)的不一致性問題,縮短了開發(fā)周期,解決了從分析和設(shè)計(jì)到軟件模塊結(jié)構(gòu)之間多次轉(zhuǎn)換映射的繁雜過程,是一種很有發(fā)展前途的系統(tǒng)開發(fā)方法[3]。Qt是一個(gè)先進(jìn)的,面向?qū)ο蟮?,跨平臺(tái)的圖形開發(fā)庫(kù),其主要優(yōu)點(diǎn)是: 優(yōu)良的跨平臺(tái)特性,支持Windows、Linux操作系統(tǒng);面向?qū)ο筇匦裕己梅庋b機(jī)制使得Qt的模塊化程度非常高,可重用性較好,對(duì)于用戶開發(fā)來說是非常方便的;豐富的API,包括多達(dá)250個(gè)以上的具有強(qiáng)大功能的C++類[4]。
3.1 事件模型實(shí)現(xiàn)
Qt本身包含一套事件模型,我們根據(jù)自己事件模型的設(shè)計(jì),在Qt事件的基礎(chǔ)上,利用面向?qū)ο蟮呐缮匦訹5],進(jìn)行擴(kuò)展,形成事件模型NewsEvent,整個(gè)通信框架都使用NewsEvent進(jìn)行通信,主要實(shí)現(xiàn)代碼如下:
#define NEInvalid -1 //無效事件ID
//模塊的identify_key,也作為_senderId or_recverId:
#define NewsMain_ID0
#define Area_ID 1
#define Seis_ID2
class NewsEvent:public QEvent //在QEvent基礎(chǔ)上進(jìn)行擴(kuò)展
{//下邊是進(jìn)程間需要傳遞的核心數(shù)據(jù),一共132個(gè)字節(jié)
(32位系統(tǒng))
long_senderId; //發(fā)送模塊的identify_key
int_recverId; //接收模塊的identify_key,發(fā)給所有帶這個(gè)識(shí)別
key的模塊
int_eventId; //事件ID:普通事件ID必須>0,<=0的事件ID用作
特殊系統(tǒng)管理
union EventData//事件攜帶的信息,可以根據(jù)事件id約定如何
使用其中的相關(guān)數(shù)據(jù)項(xiàng)
{char charValue[120];
short shortValue[60];
int intValue[30];
float floatValue[30];
double doubleValue[15];
}_eventData;
};
在事件ID的定義方面,提供了統(tǒng)一的事件ID定義函數(shù),可以對(duì)不同模塊的事件ID進(jìn)行管理,避免不同模塊間事件ID的沖突。
//NEMAKER是事件ID生成器:用模塊標(biāo)志頭組合內(nèi)部ID,
生成惟一的事件ID
#define NEMAKER(frame,id) NEMAKER_p(frame,id)
#define NEMAKER_p(frame,id) frame##id
/****各類模塊事件標(biāo)志頭****/
#define NENewsMain 10
#define NEArea 11
#define NESeis 12
//###系統(tǒng)管理###
#define NEClientRegister -998 //client向通信服務(wù)進(jìn)程注冊(cè)自己
#define NEClientUnregister -999 //client向通信服務(wù)進(jìn)程注銷自己
//###剖面模塊###
#define NEMousePositionInSection NEMAKER(NESeis,0)
//鼠標(biāo)在剖面上的位置
#define NEInterpretDataChangeInSection NEMAKER(NESeis,1)
//剖面上解釋數(shù)據(jù)變動(dòng)
各個(gè)模塊根據(jù)自己的需求,定義自己的事件ID,并約定好事件所攜帶的信息,以NewsEvent對(duì)象的形式通過框架接口將事件發(fā)送出去,接收時(shí),通過框架接口接收NewsEvent對(duì)象,并進(jìn)行處理。
3.2 通信框架實(shí)現(xiàn)
基于Qt的事件傳遞機(jī)制,開發(fā)軟件通信框架。因?yàn)镼t提供了完善的對(duì)象間(同一進(jìn)程內(nèi))傳遞事件的機(jī)制,通信框架可以把軟件模塊作為對(duì)象,利用Qt進(jìn)行事件傳遞。我們的主要工作是實(shí)現(xiàn)發(fā)送/接收事件的標(biāo)準(zhǔn)接口,進(jìn)程間通信組件,進(jìn)程間通信服務(wù)程序及進(jìn)程內(nèi)通信服務(wù)對(duì)象。
⑴ 發(fā)送/接收事件標(biāo)準(zhǔn)接口
void SendNewsEvent(QObject* target,NewsEvent* event); //發(fā)送事件
virtual void ProcessNewsEvent(NewsEvent* event); //接收事件
所有需要發(fā)送事件的模塊都使用SendNewsEvent發(fā)送事件,所有需要接收事件的模塊都重新實(shí)現(xiàn)ProcessNewsEvent虛函數(shù),進(jìn)行事件處理。在進(jìn)程間通信中,SendNewsEvent函數(shù)中的target是模塊自己的通信組件,由通信組件將事件發(fā)送給通信服務(wù)程序。在進(jìn)程內(nèi)通信中,target是進(jìn)程內(nèi)惟一的通信服務(wù)對(duì)象。
⑵ 進(jìn)程間通信組件
進(jìn)程間通信組件用于進(jìn)程間通信框架,它是模塊與通信服務(wù)程序的連接橋梁,模塊通過通信組件向通信服務(wù)程序注冊(cè)自己,發(fā)送事件,接收事件,通信服務(wù)程序通過通信組件向模塊轉(zhuǎn)發(fā)事件??紤]到跨平臺(tái)的兼容性,通信組件使用套接字(Socket)作為事件的載體,在模塊和通信服務(wù)程序間傳遞數(shù)據(jù)。
在進(jìn)程間通信中,模塊并不是直接將NewsEvent發(fā)送給通信服務(wù)程序,而是發(fā)送給進(jìn)程間通信組件,由其將事件發(fā)送到通信服務(wù)程序,同樣,通信服務(wù)程序發(fā)來的事件也是由通信組件接收,再發(fā)送給目標(biāo)模塊。
void ClientRegister(); //模塊調(diào)用其向通信服務(wù)程序進(jìn)行注冊(cè)
void ClientUnregister(); //模塊調(diào)用其向通信服務(wù)程序進(jìn)行注銷
void TransNewsEvent(NewsEvent* event,QHostAddress &ip,
quint16 port); //發(fā)送事件到服務(wù)程序
void ReceiveNewsEvent(NewsEvent* event); //從服務(wù)程序接收事件
⑶ 通信服務(wù)程序/通信服務(wù)對(duì)象
通信服務(wù)程序和通信服務(wù)對(duì)象的主要功能相同,都是管理模塊的注冊(cè)與注銷,并負(fù)責(zé)把發(fā)送給它的事件轉(zhuǎn)發(fā)到已注冊(cè)的相關(guān)模塊中。區(qū)別在于通信服務(wù)程序管理進(jìn)程間的模塊通信,而通信服務(wù)對(duì)象管理進(jìn)程內(nèi)的模塊通信。
void RegisterModule(); //模塊注冊(cè)
void UnregisterModule(); //模塊注銷
void DispatchNewsEvent(NewsEvent* event); //轉(zhuǎn)發(fā)模塊事件
事件在進(jìn)程間和進(jìn)程內(nèi)傳遞方式的區(qū)別由通信框架進(jìn)行封裝,對(duì)模塊而言,它面向的是統(tǒng)一的軟件通信框架,只需要按照框架規(guī)范開發(fā),就可以進(jìn)行通信。
4 結(jié)束語
本文描述了一種軟件通信框架的設(shè)計(jì)過程,并給出了一個(gè)較為簡(jiǎn)單的通信框架實(shí)現(xiàn)。它基于面向?qū)ο蟮脑O(shè)計(jì)方法,使用C++編程語言,利用Qt開發(fā)庫(kù)來進(jìn)行實(shí)現(xiàn)。使用基于統(tǒng)一事件模型的軟件通信框架可以減少模塊通信復(fù)雜度,縮短軟件通信功能開發(fā)周期,提高軟件可維護(hù)性,而且利于擴(kuò)展和移植。然而面對(duì)軟件系統(tǒng)中繁多的通信需求,目前還無法在本框架內(nèi)考慮周全,只有在不斷迭代細(xì)化框架的過程中,才能使問題逐一明了。目前,此軟件通信框架已在“NEWS油氣勘探綜合解釋系統(tǒng)”中得到應(yīng)用,能完全滿足解釋系統(tǒng)需求,應(yīng)用效果較好。
參考文獻(xiàn):
[1] 王宏琳.地球物理軟件體系結(jié)構(gòu)研究[J].石油地球物理勘探,2008.43
(5):606-611
[2] 李卓桓.Linux網(wǎng)絡(luò)編程[M].機(jī)械工業(yè)出版社,2000.
[3] C.Thomas Wu.面向?qū)ο蟪绦蛟O(shè)計(jì)導(dǎo)論[M].電子工業(yè)出版社,2000.
[4] Xteam軟件技術(shù)有限公司.Qt程序設(shè)計(jì)[M].清華大學(xué)出版社,2002.
[5] 錢能.C++程序設(shè)計(jì)教程[M].清華大學(xué)出版社,1999.