动态加载.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 ...
随机推荐
- 初见spark-01
今天我们来学习spark,spark是一种快速,通用,可扩展的大数据分析引擎,现已成为Apache顶级项目,Spark是MapReduce的替代方案,而且兼容HDFS,Hive,可融入Hadoop的生 ...
- 算法学习记录-图——应用之关键路径(Critical Path)
之前我们介绍过,在一个工程中我们关心两个问题: (1)工程是否顺利进行 (2)整个工程最短时间. 之前我们优先关心的是顶点(AOV),同样我们也可以优先关心边(同理有AOE).(Activity On ...
- 2139: road
把a[i], b[i]分开来排序 对应位置上的点连边 感性理解这是最小的 会连出若干个环 要使得若干个环连成大环 令a[i]向b[i - 1] 连边 易证一定能使图联通 感性理解这也是最小的 #inc ...
- NetCore log4net 集成以及配置日志信息不重复显示或者记录
NetCore log4net 集成,这是一个很常见而且网上大批大批的博文了,我写这个博文主要是为了记录我在使用过程中的一点小收获,以前在使用的过程中一直没有注意但是其实网上说的不清不楚的问题. 官方 ...
- Postman-进阶(2)
Postman-进阶(2) Postman-简单使用 Postman-进阶使用 Postman-CI集成Jenkins 管理请求 保存请求-添加“打开百度首页请求” 设置请求方式为Get,地址为www ...
- Android如何实现毛玻璃效果之Android高级模糊技术
自从iOS系统引入了Blur效果,也就是所谓的毛玻璃.模糊化效果,磨砂效果,各大系统就开始竞相模仿,这是怎样的一个效果呢,我们先来看一下,如下面的图片: 效果我们知道了,如何在Android中实现呢, ...
- 剑指Offer - 九度1349 - 数字在排序数组中出现的次数
剑指Offer - 九度1349 - 数字在排序数组中出现的次数2013-11-23 00:47 题目描述: 统计一个数字在排序数组中出现的次数. 输入: 每个测试案例包括两行: 第一行有1个整数n, ...
- 《Cracking the Coding Interview》——第18章:难题——题目10
2014-04-29 04:22 题目:给定一堆长度都相等的单词,和起点.终点两个单词,请从这堆单词中寻找一条变换路径,把起点词变成终点词,要求每次变换只能改一个字母. 解法:Leetcode中有Wo ...
- 《Cracking the Coding Interview》——第1章:数组和字符串——题目3
2014-03-18 01:32 题目:对于两个字符串,判断它们是否是Anagrams. 解法:统计俩单词字母构成是否相同即可. 代码: // 1.3 Given two strings, write ...
- CentOS搭建pptpd服务笔记
pptpd.rpm 包下载.http://poptop.sourceforge.net/yum/stable/packages/ 参考资料:http://www.oschina.net/questio ...