APP下载

基于统一事件模型的软件通信框架设计与实现

2012-04-29庞锐吕达陈科

计算机时代 2012年11期
关键词:面向对象

庞锐 吕达 陈科

摘要: 针对现代软件系统中模块协同工作的通信需求,提出了一个软件通信框架的完整实现方案。通过分析软件系统中对模块通信的要求,建立统一的事件模型,完成进程间、进程内通信框架设计,并利用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.

猜你喜欢

面向对象
面向对象方法在水蓄冷PLC编程中应用分析
基于python的面向对象传感器库类抽象方法
面向对象的计算机网络设计软件系统的开发
面向对象的数据交换协议研究与应用
面向对象Web开发编程语言的的评估方法
基于面向对象的Office评测系统的分析
峰丛洼地农作物面向对象信息提取规则集
基于E-cognition的面向对象的高分辨率遥感图像分类研究
基于面向对象的车辆管理软件的研制与开发
面向对象的SoS体系结构建模方法及应用