C语言插件机制(下) 转

[img][/img]http://www.iteye.com/topic/747159
前言
上一篇文章简单介绍了*NIX下的动态库的使用,我们在这篇文章中实现一个计算器,计算器程序calc本身不做运算,只是将操作数传递给具体的插件(adder, suber, muler, diver)来完成实际运算。首先,计算器根据插件配置文件plugin.xml来确定插件的位置,名称,入口符号的定义,然后依次调用各个插件完成计算。



插件列表
文中涉及到的插件定义在plugin.xml中,文档结构如下:




Xml代码
<plugins>  
<plugin name="adder">
<library path="/home/juntao/.libs/adder.so">
</library>
<entry name="add">
</entry>
</plugin>
<plugin name="suber">
<library path="/home/juntao/.libs/suber.so">
</library>
<entry name="sub">
</entry>
</plugin>
<plugin name="muler">
<library path="/home/juntao/.libs/muler.so">
</library>
<entry name="mul">
</entry>
</plugin>
<plugin name="diver">
<library path="/home/juntao/.libs/diver.so">
</library>
<entry name="div">
</entry>
</plugin>
</plugins>

<plugins>
<plugin name="adder">
<library path="/home/juntao/.libs/adder.so">
</library>
<entry name="add">
</entry>
</plugin>
<plugin name="suber">
<library path="/home/juntao/.libs/suber.so">
</library>
<entry name="sub">
</entry>
</plugin>
<plugin name="muler">
<library path="/home/juntao/.libs/muler.so">
</library>
<entry name="mul">
</entry>
</plugin>
<plugin name="diver">
<library path="/home/juntao/.libs/diver.so">
</library>
<entry name="div">
</entry>
</plugin>
</plugins>

每个插件为一个plugin标签,plugin标签中包含library, entry两个字标签,分别定义动态库文件的路径及名称和插件函数的入口。为了简便,我们不重复设计list及xml解析,这里使用libxml2作为xml的分析器,GLIB中的GSList(单链表)来作为插件列表的链表对象。



每一个插件在C语言中的定义如下,非常简单(plugin.h)




C代码
#ifndef _PLUGIN_H_   
#define _PLUGIN_H_

typedef struct{
char name[64];
char path[256];
char entry[128];
int version;
}Plugin;

#endif

#ifndef _PLUGIN_H_
#define _PLUGIN_H_

typedef struct{
char name[64];
char path[256];
char entry[128];
int version;
}Plugin;

#endif


这里为了行文方便,Plugin结构中的字符串为静态尺寸。



计算器
计算器调用parseconf模块中的load_plugins将plugin.xml中定义的Plugin加载进一个GSList,以备后用:




C代码
#include "plugin.h"   

extern int load_plugins(char *config, GSList **list);

#include "plugin.h"

extern int load_plugins(char *config, GSList **list);

插件中的函数原型应该符合接口定义:




C代码
//pointer to function, which return a double, and get 2 double as input   
double (*pfunc)(double a, double b);

//pointer to function, which return a double, and get 2 double as input
double (*pfunc)(double a, double b);


计算器的主要代码如下:


C代码
int calc_test(double a, double b){   
GSList *list = NULL, *it = NULL;
Plugin *pl = NULL;

//insert a null node into list at first
list = g_slist_append(list, NULL);

int code = 0;
double result;

//load plugin defined in plugin.xml into list
load_plugins("plugin.xml", &list);

for(it = list; it != NULL; it = it->next){
pl = (Plugin *)it->data;
if(pl == NULL){
continue;
}else{
//open the library
flib = dlopen(pl->path, RTLD_LAZY);
dlError = dlerror();

if(dlError){
fprintf(stderr, "open %s failed\n", pl->name);
g_slist_free(list);
return -1;
}

//get the entry
*(void **)(&pfunc) = dlsym(flib, pl->entry);
dlError = dlerror();
if(dlError){
fprintf(stderr, "find symbol %s failed\n", pl->entry);
g_slist_free(list);
return -1;
}

//call the function
result = (*pfunc)(a, b);
printf("%s(%f, %f) = %f\n", pl->entry, a, b, result);

//then close it
code = dlclose(flib);
dlError = dlerror();

if(code){
fprintf(stderr, "close lib error\n");
g_slist_free(list);
return -1;
}
}
}

g_slist_free(list);
return 0;
}

int calc_test(double a, double b){
GSList *list = NULL, *it = NULL;
Plugin *pl = NULL;

//insert a null node into list at first
list = g_slist_append(list, NULL);

int code = 0;
double result;

//load plugin defined in plugin.xml into list
load_plugins("plugin.xml", &list);

for(it = list; it != NULL; it = it->next){
pl = (Plugin *)it->data;
if(pl == NULL){
continue;
}else{
//open the library
flib = dlopen(pl->path, RTLD_LAZY);
dlError = dlerror();

if(dlError){
fprintf(stderr, "open %s failed\n", pl->name);
g_slist_free(list);
return -1;
}

//get the entry
*(void **)(&pfunc) = dlsym(flib, pl->entry);
dlError = dlerror();
if(dlError){
fprintf(stderr, "find symbol %s failed\n", pl->entry);
g_slist_free(list);
return -1;
}

//call the function
result = (*pfunc)(a, b);
printf("%s(%f, %f) = %f\n", pl->entry, a, b, result);

//then close it
code = dlclose(flib);
dlError = dlerror();

if(code){
fprintf(stderr, "close lib error\n");
g_slist_free(list);
return -1;
}
}
}

g_slist_free(list);
return 0;
}

首先,定义一个GSList,然后将其传递给load_plugins,load_plugins解析plugin.xml,然后填充list返回,calc_test遍历插件列表,并调用每一个插件定义的entry.



除法器
我们来看一个具体的插件:做除法的模块




C代码
#include <stdio.h>   

double div(double a, double b){
if(b == 0){
fprintf(stderr, "div zero error\n");
return -1;
}else{
return a / b;
}
}

#include <stdio.h>

double div(double a, double b){
if(b == 0){
fprintf(stderr, "div zero error\n");
return -1;
}else{
return a / b;
}
}
diver.c在编译之后,生成diver.so,将其置于plugin.xml定义的位置处即可。



运行结果如下图所示:

[img]http://dl.iteye.com/upload/attachment/298638/28680c91-d56d-3a73-aca1-4f3d8d68c151.png[/img]

其他代码如xml的解析,GSList的使用等与插件机制关系不大,感兴趣的朋友可以在附件中查看。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值