背景:不同产品组将其功能编译为.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文件并执行类函数的更多相关文章

  1. 动态加载JS文件,并根据JS文件的加载状态来执行自己的回调函数

    动态加载JS文件,并根据JS文件的加载状态来执行自己的回调函数, 在很多场景下,我们需要在动态加载JS文件的时候,根据加载的状态来进行后续的操作,需要在JS加载成功后,执行另一方法,这个方法是依托在加 ...

  2. Android应用安全之外部动态加载DEX文件风险

    1. 外部动态加载DEX文件风险描述 Android 系统提供了一种类加载器DexClassLoader,其可以在运行时动态加载并解释执行包含在JAR或APK文件内的DEX文件.外部动态加载DEX文件 ...

  3. 两种动态加载JavaScript文件的方法

    两种动态加载JavaScript文件的方法 第一种便是利用ajax方式,第二种是,动静创建一个script标签,配置其src属性,经过把script标签拔出到页面head来加载js,感乐趣的网友可以看 ...

  4. 详谈LABJS按需动态加载js文件

    为了提高页面的打开和加载速度,我们经常把JS文件放在页面的尾部,但是有些JS必须放在页面前面,这样就会增加页面的加载时间:于是出现了按需动态加载的概念,这个概念就是当页面需要用到这个JS文件或者CSS ...

  5. Java_Java中动态加载jar文件和class文件

    转自:http://blog.csdn.net/mousebaby808/article/details/31788325 概述 诸如tomcat这样的服务器,在启动的时候会加载应用程序中lib目录下 ...

  6. js动态加载css文件和js文件的方法

    今天研究了下js动态加载js文件和css文件的方法. 网上发现一个动态加载的方法.摘抄下来,方便自己以后使用 [code lang="html"] <html xmlns=& ...

  7. QUiLoader 动态加载.ui文件

    动态加载UI文件是指,用 Qt Designer 通过拖拽的方式生产.ui 文件.不用 uic工具把.ui 文件变成等价的 c++代码,而是在程序运行过程中需要用到UI文件时,用 QUiLoader ...

  8. 详解QUiLoader 动态加载.ui文件

    http://blog.chinaunix.net/uid-13838881-id-3652523.html 1.适用情况: 动态加载UI文件是指,用 Qt Designer 通过拖拽的方式生产.ui ...

  9. ExtJS4.x动态加载js文件

    动态加载js文件是ext4.x的一个新特性,可以有效的减少浏览器的压力,提高渲染速度.如动态加载自定义组件 1.在js/extjs/ux目录下,建立自定义组件的js文件. 2.编写MyWindow.j ...

随机推荐

  1. [BZOJ1899]Lunch 午餐(DP)

    [BZOJ1899] 首先有个很贪心的思路,吃饭时间长的最先打饭为最优,所以开始先排个序 然后考虑DP,我们不需要知道某个人在哪个对,只要关注总的时间就行了 肯定需要一维表示当前同学编号,还需要表示某 ...

  2. 移动端的拖拽排序在react中实现 了解一下

    最近做一个拖拽排序的功能找了好几个有一个步骤简单,结合redux最好不过了,话不多说上代码 第一步: npm install react-draggable-tags --save 第二步 sort. ...

  3. 笔记-pytho-语法-yield

    笔记-python-语法-yield 1.      yield 1.1.    yield基本使用 def fab(max): n,a,b = 0, 0, 1 while n < max: y ...

  4. wlr快捷键

    ref:http://www.cnblogs.com/zhangyang/archive/2011/07/22/2113856.html   Windows Live Writer提供了许多方便的快捷 ...

  5. 十二、mysql之视图,触发器,事务等

    一.视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,可以将该结果集当做表来使用. 使用视图我们可以把查询过程中的 ...

  6. 001.我的第一个Java程序

    第一步安装JDK 第二步设置PATH路径 设置Windows的PATH 路径 方法一:直接设置添加PATH C:\Program Files\Java\jdk1.8.0_92\bin 方法二: 先增加 ...

  7. 一步一步学Linq to sql(一):预备知识

    什么是Linq to sql Linq to sql(或者叫DLINQ)是LINQ(.NET语言集成查询)的一部分,全称基于关系数据的 .NET 语言集成查询,用于以对象形式管理关系数据,并提供了丰富 ...

  8. JavaSE总结--面向对象

    封装: 1)为什么要用private修饰 保护属性或方法不被别人随意调用. 继承: 继承模型: 多态: 接口: 抽象类: 内部类: 在编译时用$分隔. 访问局部变量,该变量必须用final修饰. 向下 ...

  9. Pytest+allure+jenkins生成测试报告

    allure集成jenkins下载地址.下载相关版本的allure包 http://updates.jenkins-ci.org/download/plugins/allure-jenkins-plu ...

  10. python学习笔记-基础

    1.大小写敏感 2. print (n,f,s1,s2,s3,s4,sep='\n')  -- 换行输出  seq='\n' print ('n=%d'%n,'f=%f'%f,'s1=%s'%s1,' ...