Board logo

标题: 分布式应用中基于事件驱动的应用开发模型 [打印本页]

作者: look_w    时间: 2018-4-15 19:58     标题: 分布式应用中基于事件驱动的应用开发模型

前言从目前看,大量数据的流动仍然主要分布在局域网的分布式系统中,该类系统的大流量、实时性的特点要求系统具有实时响应、交互动作异步非耦合、高可用性、高可得到性等特征。而因为系统主要局限在局域网内运行,因而在系统的构建上应用要具有灵活多样可靠稳定的性能。事实上,良好的局域网应用是联入广域网的前提。
在该类分布式系统中,引导数据流动和分布式动作的往往是事件的作用,或者称之为消息。事件是激活和驱动分布式系统的直接原因,也是进一步构建分布式对象管理的基础。利用事件驱动开发模型,可以快速构建分布式系统应用,提高分布式应用和整个分布式系统的运行效率。
事件驱动的开发模型首先,在分布式系统中,事件是异步非耦合的,这是系统实时性的要求。因为在分布式系统中,往往各个关键应用既是服务器应用,也是客户应用,相互之间从功能上看是对等关系,如果在同步情况下,一个应用驱动了另一个应用的事件,这个应用则必须堵塞,以等待事件执行的返回状态,这样这个应用在这段时间内则不能处理实时事件。而各个应用之间相互不完全依赖的情况也决定了分布式系统中事件的两端必须为非耦合。
事件驱动的开发模型包括如下几个部分:
Linux系统上事件驱动的开发框架目前,Linux操作系统逐渐为人们所接受,在Linux上的分布式系统也逐渐获得了更广泛的应用。本文在这里描绘了在Linux系统上基于以上事件驱动模型的简化开发框架。基于这个框架,还可以在Linux上开发出实用、可靠、稳定的事件驱动软件包。
2.1 事件定义库
事件定义库记录了应用所关心的所有事件信息,是事件测试模块的扫描数据区。定义库要求查询方便快速,定义库可以自由扩展。例如可以用以下的结构实现:      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
typedef struct {
     // 指向下一个事件信息的指针
     void *ptr;
     // 事件ID
int event_id;
// 事件属性,指示事件是否活动等。
     int event_propertiy;
     // 定义事件的数据内容
     struct event_info info;
     // 事件处理例程,包括了数据信息和信道信息
     int (int *)(*event_process*)(void *data_buff, void *channel_info);
} event_table
struct event_db {
     // 有效的事件数量
     int event_num;
     // 事件列表
     event_table *event;
}




2.2 事件检测模块
事件的检测是通过对一系列感兴趣的文件描述符的检测来完成的。感兴趣的文件描述符包括在文件描述符集内,一个感兴趣的文件描述符对应于一类事件。当我们检测到一个文件描述符可读时,就知道应用内已经驱动了一个事件。通过扫描事件定义库可以找到相应的事件,然后就可以提交给事件执行模块。      
可以用如下代码实现事件检测模块:
1
2
3
4
5
6
7
8
9
10
11
12
int rts;
fd_set fdset;
......
rts = select(FD_SETSIZE,&fdset,NULL,NULL,NULL,0);
if(rts > 0 ) {
     if(rts == ......) { /* 如果检测到I/O描述符为某一类型的描述符,则*/
         ......      /* 将数据提交给事件执行模块 */
     }
     else if(rts == ......) {
         ......
     }
}




2.3 事件注册模块
事件要注册后,应用才可以辨识并驱动该事件。事件的注册过程实际上是定义事件信息,将信息写入事件定义库的过程。      
2.4 事件信道
事件信道不仅定义了事件流动的基础设施,也定义了相应的事件I/O描述符。例如在一个应用内部的驱动事件,事件信道的实现可以采用命名管道,返回的描述符用于检测内部的驱动事件。可以用以下代码实现:      
1
2
3
int io_inner
mkfifo(fifo_filename,mode) // 创建一个FIFO文件
io_inner = open(fifo_filename, mode); // 获得该文件描述符




应用之间的驱动事件的信道要用到socket描述符。应用之间建立了socket链路后即建立了事件流动的信道,返回的socket描述符用于检测应用之间的驱动事件。各种类型的信道均可加入检测的I/O描述符集。注意,对应于服务器端,执行如下代码:         
1
int sock = socket(......),




返回的描述符可以直接加入检测描述符集,而当在检测到客户连接后,返回新的描述符也要加入检测描述符集,因为这个描述符才是检测驱动事件的描述符。如将创建的sock加入检测描述符集:         
1
FD_SET(sock, &fdset);




2.5 事件执行模块
当有驱动事件时,事件检测模块将调用事件的执行模块,事件的执行模块则接收事件数据信息,同时解析事件驱动源信息和信道信息。      
对应应用内部驱动事件,当检测到命名管道描述符可读时,则检测事件定义库,当事件处于活动时,则接收定义库内缓冲区的数据执行该事件例程。对应于应用之间的驱动事件,则当检测到socket描述符可读时,启动如下代码:         
1
rts = recv(sock, (void *) buff, ......)




接收到事件数据后,检测头部信息,取出要驱动的事件ID,连通接收的通信数据提交给事件处理例程。
2.6 事件的驱动
对应应用内部事件,一方面通过命名管道通知检测模块,另一方面,要把事件的数据写入定义库,并设置事件处于活动状态。而应用之间的驱动事件,对数据进行封装和编码后,在底层要用如下socket函数发送:         
1
rts = send(sock, (void *) buff, ......);




安装如上的驱动事件开发框架,可以在Linux较快的开发出相应的软件包。      
结束语该开发模型事件驱动的细节都封装在内部,总体结构清晰明了,只留了一些注册、驱动事件的接口给应用开发程序员。有了基于事件驱动软件包后,可以继续开发分布式对象管理,增强分布式系统的构建能力。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0