动态加载.so文件并执行类函数
背景:不同产品组将其功能编译为.so,这些.so 可以加载到统一的基础平台上运行,如果产品组代码有改动,只需要更新对应的.so
问题:如何动态加载.so文件,并使用里边的函数/类 ?
解决方法1: 使用类的多态特性,将各种产品功能抽象为“工作类”,这些“工作类”都继承一个“动态加载基类”,然后定义纯C的类创建和销毁函数,产品功能.so加载进来后,基础平台寻找创建和销毁函数,就可以创建一个“工作类”实例,并通过基类指针使用。下面是示例代码
class worker_base {
protected:
int wtype;
public:
worker_base():wtype(){}
virtual ~worker_base(){}
void settype(int type)
{
wtype = type;
}
virtual int doJob() = ;
};
typedef worker_base * create_t();
typedef void destroy_t(worker_base *);
上图是worker_base.h, 定义了worker_base类,这个类是一个基类,工作函数 doJob 定义为纯虚函数,同时,定义基类的创建和销毁函数指针 create_t 和 destroy_t
#include <string>
#include "worker_base.h" namespace worker{ class worker : public worker_base{
public:
worker(){}
~worker(){} public : virtual int doJob() {
printf("dojob in module X \n ");
return ;
} }__rte_cache_aligned; }
上图是worker.h , 定义class worker 为具体的产品工作类,继承 work_base, 并实现自己的 doJob
#include <stdio.h>
#include "worker.h" worker::worker * wk = NULL; extern "C" worker_base* create(){
printf("create report\n");
wk = new worker::worker();
return wk;
} extern "C" void destroy(worker_base* rpt)
{
printf("delete report\n");
//delete rpt;
}
上图为worker.cpp , 实现了worker 类实例的创建和销毁函数
#include <string>
#include <list>
#include <dlfcn.h> #include "worker_base.h"
#include "DomParser.h" /// worker list
typedef std::list<worker_base*>::iterator worker_iter;
enum hooktype { WK };
class Register
{
public:
Register(){};
~Register(){}; public:
std::list<worker_base*> worker_list; private:
bool parse();
bool hook_register(hooktype ht, void* hk);///<Register one hook function into the list
bool invoke_method(const std::string& hooktype, const std::string& libname);
bool init();
bool run();
public:
inline static Register& instance()
{
extern Register __g_reg;
return __g_reg;
}
};
static inline Register& GetHook() {
return Register::instance();
}
上图是register.h , 定义了一个注册类,该类通过一个链表维护所以工作类实例,parse 函数解析XML文件,将产品.so加载进来,dlsym 寻找create_t和delete_t符号,创建实例然后插入链表。主流程通过调用链表里的实例的run方法完成对.so类的调用,下面是加载一个.so的方法
#include <strsplit.h>
#include <iostream>
#include "register.h" Register __g_reg;
/*将一个worker实例(基类指针)注册到链表*/
bool Register::hook_register(hooktype ht, void* hk)
{
if(ht == WK){
worker_list.push_back((worker_base*)hk);
}else{
printf("hook typedef error\n");
return false;
}
return true;
} bool Register::parse()
{
const std::string& fname("./model.xml");
nsfocus::DomParser parser;
try{
if(parser.open(fname)){
xercesc::DOMNode* node;
xercesc::DOMNode* root = parser.getRootNode();
node = nsfocus::DomUtil::getChildNode(root, "modules/netio", "/");
std::string hooktype;
std::string val;
nsfocus::DomUtil::getAttribNodeValue<std::string>(node, "hooktype", hooktype);
nsfocus::DomUtil::getAttribNodeValue<std::string>(node, "files_list", val);
size_t toks = ;
nsfocus::strsplit split(val, " ", true, , toks, '\0');
for(size_t i=;i<toks;i++){ if(!invoke_method(hooktype, split[i]))
return false;
}
}else{
printf("open confile error: %s\n", fname.c_str());
return false;
}
}catch(...){
printf("catch: DomParser init error\n");
return false;
}
return true;
}
/*使用dlopen接口打开一个.so文件,通过dlsym接口寻找create和destroy的符号表
对应的地址,这两个地址就是.so工作类实例创建和销毁的函数*/
bool Register::invoke_method(const std::string& hooktype, const std::string& libname)
{
std::string lib = "./" + libname;
void *handler = dlopen(lib.c_str(), RTLD_NOW);
if(handler == NULL){
printf("dlopen err : %s.\n",dlerror());
return false;
} if(hooktype == "worker"){
create_t * create_worker = (create_t*) dlsym(handler,"create");
const char * dlsym_error = dlerror();
if(dlsym_error)
{
std::cerr << "load worker create error:" << dlsym_error << std::endl;
return false;
}
destroy_t * destroy_worker = (destroy_t*) dlsym(handler,"destroy");
dlsym_error = dlerror();
if(dlsym_error)
{
std::cerr << "load worker destroy error:" << dlsym_error << std::endl;
return false;
}
worker_base * w = create_worker();
return hook_register(WK, w); }else{
printf("hooktype compare failed!!\n");
return false;
}
return true;
}
/*遍历整个worker链表,调用其doJob方法*/
bool Register::run()
{
worker_iter it = worker_list.begin();
worker_iter it_end = worker_list.end();
for (; it != it_end; ++it){
(*it)->doJob();
}
return true;
} bool Register::init()
{
return parse();
}
下面是main函数
#include <stdlib.h>
#include <stdio.h>
#include "register.h" int main(){ Register & reg = GetHook();
reg.init();
reg.run();
return ;
}
下面是model.xml示例
<root>
<modules>
<netio hooktype="worker" files_list="libworker.so"/>
</modules>
</root>
参考 http://stackoverflow.com/questions/496664/c-dynamic-shared-library-on-linux
动态加载.so文件并执行类函数的更多相关文章
- 动态加载JS文件,并根据JS文件的加载状态来执行自己的回调函数
动态加载JS文件,并根据JS文件的加载状态来执行自己的回调函数, 在很多场景下,我们需要在动态加载JS文件的时候,根据加载的状态来进行后续的操作,需要在JS加载成功后,执行另一方法,这个方法是依托在加 ...
- Android应用安全之外部动态加载DEX文件风险
1. 外部动态加载DEX文件风险描述 Android 系统提供了一种类加载器DexClassLoader,其可以在运行时动态加载并解释执行包含在JAR或APK文件内的DEX文件.外部动态加载DEX文件 ...
- 两种动态加载JavaScript文件的方法
两种动态加载JavaScript文件的方法 第一种便是利用ajax方式,第二种是,动静创建一个script标签,配置其src属性,经过把script标签拔出到页面head来加载js,感乐趣的网友可以看 ...
- 详谈LABJS按需动态加载js文件
为了提高页面的打开和加载速度,我们经常把JS文件放在页面的尾部,但是有些JS必须放在页面前面,这样就会增加页面的加载时间:于是出现了按需动态加载的概念,这个概念就是当页面需要用到这个JS文件或者CSS ...
- Java_Java中动态加载jar文件和class文件
转自:http://blog.csdn.net/mousebaby808/article/details/31788325 概述 诸如tomcat这样的服务器,在启动的时候会加载应用程序中lib目录下 ...
- js动态加载css文件和js文件的方法
今天研究了下js动态加载js文件和css文件的方法. 网上发现一个动态加载的方法.摘抄下来,方便自己以后使用 [code lang="html"] <html xmlns=& ...
- QUiLoader 动态加载.ui文件
动态加载UI文件是指,用 Qt Designer 通过拖拽的方式生产.ui 文件.不用 uic工具把.ui 文件变成等价的 c++代码,而是在程序运行过程中需要用到UI文件时,用 QUiLoader ...
- 详解QUiLoader 动态加载.ui文件
http://blog.chinaunix.net/uid-13838881-id-3652523.html 1.适用情况: 动态加载UI文件是指,用 Qt Designer 通过拖拽的方式生产.ui ...
- ExtJS4.x动态加载js文件
动态加载js文件是ext4.x的一个新特性,可以有效的减少浏览器的压力,提高渲染速度.如动态加载自定义组件 1.在js/extjs/ux目录下,建立自定义组件的js文件. 2.编写MyWindow.j ...
随机推荐
- 財務会計関連(FI&CO)
[財務会計伝票]FB01: 登録FB02: 伝票変更FB09: 明細変更FB03: 照会FB04: 変更履歴照会FB08: 反対仕訳FB05: 消込転記FB50: G/L勘定伝票一般転記FB1S: 勘 ...
- 世界未解之谜之----------Android Gradle
今天运行项目,运行的debug出来的包竟然是命名过的,但是我的buildTypes里面的debug 并没有执行重命名操作.很奇怪,我的猜测是: 执行buildTypes的时候,虽然是assermdeb ...
- SetConsoleCtrlHandler
Excerpt: Registering a Control Handler Function This is an example of the SetConsoleCtrlHandler fu ...
- Robocopy.exe使用详例
Robocopy.exe使用详例 Robocopy.exe 是 微软在Windows server 2003 Resource Kit Tools 里面提供的程序来做备份的.Vis ...
- 《Cracking the Coding Interview》——第2章:链表——题目6
2014-03-18 02:41 题目:给定一个带有环的单链表,找出环的入口节点. 解法1:用hash来检测重复节点肯定是容易想而且效率也高的好办法. 代码: // 2.6 You have a ci ...
- web.xml 文件详解
目录 1. web.xml各版本区别 2. web.xml配置详解 2.1 java web项目启动加载顺序 2.2 web.xml中定义的元素 web.xml文件是Java Web项目中的一个配置文 ...
- python实现单链表的反转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #!/usr/bin/env python #coding = utf-8 ...
- 使用Ghost版本Windows7系统下载安装virtualBox和centos7异常解决
使用Ghost版本Windows7系统下载安装virtualBox和centos7异常解决: 下载安装运行virtualBox时出现获取VirtualBox对象严重错误(如图): 解决方案步骤: 在开 ...
- 第一天docker入门
[01 入门] docker 最核心为三部分组成 镜像,仓库和容器 镜像:一个只读的模板 仓库:代码仓库,镜像的集合 容器:镜像的实例化进程 我们可以这样理解 容器就是一个沙箱,docker利用容器运 ...
- 数据结构与算法之顺序表C语言实现
顺序表等相关概念请自行查阅资料,这里主要是实现. 注: 1.顺序表C语言实现: 2.按较简单的方式实现,主要帮助理解,可在此基础上修改,更加完善: 3.提供几个简单函数,可自行添加功能: 4.可用C+ ...