背景:不同产品组将其功能编译为.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. 笔记-python-语法-property

    笔记-python-语法-property 1.      property 看到@property,不明白什么意思,查找文档了解一下. 1.1.    property类 proerty是pytho ...

  2. 搭建Linpack

    环境:vmware workstation14 + centos7(linux基本都可以) 一.开始安装mpich 1. 解决依赖gcc gcc-gfortran sudo yum install g ...

  3. 路由vue-router进阶

    目录 1. 导航守卫 1.1. 全局守卫 1.2. 全局解析守卫 1.3. 全局后置钩子 1.4. 路由独享的守卫 1.5. 组件内的守卫 1.6. 完整的导航解析流程 2. 路由元信息 3. 获取数 ...

  4. 如何写一套下拉刷新的控件?《MJRefresh原理浅析》(附Demo下载地址)

    相信大家有很多人在做项目的时候都在使用MJRefresh 控件来实现下拉刷新的功能: MJRefresh经过不断的重构与更新迭代,现在不管是功能上还是代码结构上都是相当不错的,都是很值我们去学习的. ...

  5. 利用NSAttributedString实现图文混排

    UILabel 和 UITextView 都能添加 NSAttributedString 属性字符串,通过这一点,可以实现带有属性的文字和文字内包含图片的文本内容展示. 效果如下:   1-初始化可变 ...

  6. 这是我见过最厉害的--智能代码生成器、html+js+底层+sql全都有、瓦特平台

    1:直接上图.图片有点多.我就没全部上传了. (demo.使用方法.数据库bak)下载:http://pan.baidu.com/s/1ntE5bDn 起源: 之前有好多人问我代码生成器的源码.我发了 ...

  7. 《Cracking the Coding Interview》——第5章:位操作——题目3

    2014-03-19 05:57 题目:给定一个整数N,求出比N大,而且二进制表示中和N有相同个数的‘1’的最小的数,比如3是‘11’,接下来的5是‘101’,再接下来的6是‘110’. 解法:从低位 ...

  8. 《Cracking the Coding Interview》——第3章:栈和队列——题目4

    2014-03-18 05:28 题目:你肯定听过汉诺威塔的故事:三个柱子和N个从小到大的盘子.既然每次你只能移动放在顶上的盘子,这不就是栈操作吗?所以,请用三个栈来模拟N级汉诺威塔的玩法.放心,N不 ...

  9. 嵌入式(Embedded System)笔记 —— Cortex-M3 Introduction and Basics(上)

    随着课内的学习,我想把每节课所学记录下来,以作查阅.以饲读者.由于我所上的是英文班课程,因此我将把关键术语的英文给出,甚至有些内容直接使用英文. 本次所介绍内容是关于Cortex-M3的基础内容. - ...

  10. 《数据结构》C++代码 散列表

    散列表,又名哈希表.Hash表.这是一个神奇的数据结构,它的复杂度是常数级别,由于我非常喜欢这个数据结构,在此简单介绍一下. (没有学过Hash表的同学,我推荐一个教程:http://www.cnbl ...