背景:不同产品组将其功能编译为.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. 20145202 《Java程序设计》实验四实验报告

    实验名称 Andoid开发基础 实验内容 1.基于Android Studio开发简单的Android应用并部署测试; 2.了解Android组件.布局管理器的使用: 3.掌握Android中事件处理 ...

  2. NPM安装vue-cli,并创建vue+webpack项目模板

    1.安装npm npm 是node.js 的包管理工具, 安装流程地址:https://docs.npmjs.com/cli/install  估计会非常慢,我们可以使用淘宝NPM镜像下载安装:htt ...

  3. P2183 巧克力(二分答案)

    P2183 巧克力 题目描述 佳佳邀请了M个同学到家里玩.为了招待客人,她需要将巧克力分给她的好朋友们.她有N(1<=N<=5000)块巧克力,但是大小各不一样,第i块巧克力大小为为1*X ...

  4. luogu3343 [ZJOI2015]地震后的幻想乡

    ref 前置技能是bzoj的串珠子.这种子集dp好神啊qwq. 还有这种钦定点转移子集的方法建议按这题的方法写,不要看串珠子qwq #include <iostream> #include ...

  5. R语言中的机器学习包

    R语言中的机器学习包   Machine Learning & Statistical Learning (机器学习 & 统计学习)  网址:http://cran.r-project ...

  6. 玩转Node.js(一)

    玩转Node.js(一) 在说Node.js之前,我们先来说说js,如果你也曾开发过前端,那么你一定接触到了这个叫JavaScript有趣的东西,而对于JavaScript,你只会基本的操作——为we ...

  7. 【Lowest Common Ancestor of a Binary Search Tree】cpp

    题目: Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in th ...

  8. JavaScript简易学习笔记

    学习地址:http://www.w3school.com.cn/js/index.asp 文字版: https://github.com/songzhenhua/github/blob/master/ ...

  9. 在cmd运行脚本

    1.打开cmd 2.cd到脚本目录,运行所有脚本的上级目录,我的是cd C:\Users\Administrator\PycharmProjects\webtest\TestSuit 3.使用Pyth ...

  10. 孤荷凌寒自学python第十七天初识Python的函数

    孤荷凌寒自学python第十七天初识Python的函数 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 函数是能够完成指定运算并返回运算结果的代码块.是结构化编程重要的结构. 我首先发现pyt ...