最新电子科大李老师Linux实验四.docx

上传人:b****3 文档编号:5304134 上传时间:2022-12-15 格式:DOCX 页数:18 大小:291.01KB
下载 相关 举报
最新电子科大李老师Linux实验四.docx_第1页
第1页 / 共18页
最新电子科大李老师Linux实验四.docx_第2页
第2页 / 共18页
最新电子科大李老师Linux实验四.docx_第3页
第3页 / 共18页
最新电子科大李老师Linux实验四.docx_第4页
第4页 / 共18页
最新电子科大李老师Linux实验四.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

最新电子科大李老师Linux实验四.docx

《最新电子科大李老师Linux实验四.docx》由会员分享,可在线阅读,更多相关《最新电子科大李老师Linux实验四.docx(18页珍藏版)》请在冰豆网上搜索。

最新电子科大李老师Linux实验四.docx

最新电子科大李老师Linux实验四

 

电子科大李老师Linux实验四

电子科技大学

实验报告

学生姓名:

学号:

指导教师:

李林

实验地点:

实验时间:

Csdn全部资源下载地址:

一、实验室名称:

Linux环境高级编程实验室

二、实验项目名称:

插件框架实验

三、实验学时:

4学时

四、实验目的:

需要说明为什么要进行本次实验

五、实验内容:

⏹版本1:

开发一个程序,向屏幕打印“HelloWorld”;

在不重新编译链接原程序的前提下,将打印的文字改为“HelloChina”

思想:

将打印函数编译为一个动态链接库文件,然后测试程序用显式调用的方式,加载动态链接库,并调用其中的打印函数。

此后要改变输出内容,只需要重新编译动态链接库文件,而无需对测试程序进行修改。

动态链接库源文件代码(导出打印函数),print.cpp:

#include

usingnamespacestd;

//打印函数定义

extern"C"voidPrint()

{

cout<<"HelloWorld!

"<

}

测试程序源代码,test.cpp:

#include

#include

usingnamespacestd;

//主程序,测试动态链接库

intmain()

{

//打开动态链接库文件

void*handle=dlopen("./libprint.so",RTLD_LAZY);

if(handle==0)//打开失败

{

cout<<"dlopenerror"<

return0;

}

//定义一个函数指针类型

typedefvoid(*FUNC_PRINT)();

//映射打印函数地址

FUNC_PRINTdl_print=(FUNC_PRINT)dlsym(handle,"Print");

if(dl_print==0)

{

cout<<"dlsymerror"<

return0;

}

//调用打印函数

(dl_print)();

//卸载动态链接库

dlclose(handle);

return0;

}

先编译测试程序

再编译动态链接库

运行测试程序,输出HelloWorld

修改print.cpp里的输出内容为HelloChina

重新编译动态链接库文件之后,再运行测试程序,输出了HelloChina

⏹版本2要求:

同时要打印“HelloWorld”,打印“HelloChina”,甚至同时打印未来才会增加的其他打印信息

打印未来的这些信息,也不能重新编译链接原程序

思想:

使用插件的思想,将所有的动态链接库文件放置在一个plugin的文件夹中,然后测试程序去遍历该目录,依次打开所有的动态链接库文件,并调用其中的Print函数。

另外遍历目录获取动态链接库文件名这个任务,定义一个单独的工具类来实现。

第一个动态链接库源代码,print_world.cpp:

#include

usingnamespacestd;

//打印函数定义

extern"C"voidPrint()

{

cout<<"HelloWorld!

"<

}

第二个动态链接库源代码,print_china.cpp:

#include

usingnamespacestd;

//打印函数定义

extern"C"voidPrint()

{

cout<<"HelloChina!

"<

}

插件文件搜索类头文件,CPluginSeacher.h:

#ifndefCPLUGINSEARCHER_H

#defineCPLUGINSEARCHER_H

#include

#include

usingnamespacestd;

//插件搜索类声明

classCPluginSeacher

{

public:

CPluginSeacher();

virtual~CPluginSeacher();

//获取所有的插件文件名

boolGetPluginNames(vector&vstrPluginNames);

};

#endif

插件文件搜索类源文件,CPluginSeacher.cpp:

#include"CPluginSeacher.h"

#include

#include

CPluginSeacher:

:

CPluginSeacher()

{

}

CPluginSeacher:

:

~CPluginSeacher()

{

}

//获取所有的插件文件名

boolCPluginSeacher:

:

GetPluginNames(vector&vstrPluginNames)

{

//打开当前目录下的plugin目录

DIR*dir=opendir("./plugin");

if(dir==0)

returnfalse;

//循环读取所有文件

for(;;)

{

//读一个文件

structdirent*pentry=readdir(dir);

if(pentry==0)

break;

//当前目录,跳过

if(strcmp(pentry->d_name,".")==0)

continue;

//上级目录,跳过

if(strcmp(pentry->d_name,"..")==0)

continue;

//其它文件,则加上目录前缀,保存到数组中

stringstr="./plugin/";

str+=pentry->d_name;

vstrPluginNames.push_back(str);

}

//关闭目录

closedir(dir);

returntrue;

}

测试程序源文件,test.cpp:

#include

#include

#include"CPluginSeacher.h"

usingnamespacestd;

//主程序,测试遍历目录,调用所有动态链接库

intmain()

{

//存放所有动态链接库的文件名

vectorvstrPluginNames;

//定义插件搜索类对象

CPluginSeacherenumerator;

//获取所有的插件文件名

if(!

enumerator.GetPluginNames(vstrPluginNames))

{

cout<<"GetPluginNameserror"<

return0;

}

//遍历文件名数组,依次打开并调用

for(inti=0;i

{

//打开动态链接库文件

void*handle=dlopen(vstrPluginNames[i].c_str(),RTLD_LAZY);

if(handle==0)

{

cout<<"dlopenerror"<

return0;

}

//定义一个函数指针类型

typedefvoid(*FUNC_PRINT)();

//映射打印函数地址

FUNC_PRINTdl_print=(FUNC_PRINT)dlsym(handle,"Print");

if(dl_print==0)

{

cout<<"dlsymerror"<

return0;

}

//调用打印函数

(dl_print)();

//卸载动态链接库

dlclose(handle);

}

return0;

}

先编译测试程序

再编译两个插件(动态链接库)

把两个插件放到plugin目录

运行测试程序,正确调用了所有插件中定义的打印函数

⏹版本3要求:

⏹版本2是同时调用所有插件的打印功能,现在要求一次只调用一种功能

⏹3-1:

通过命令行方式:

./a.outhelp,输出所有插件实现的功能ID,以及该功能ID对应的功能描述(参考代码3)

⏹3-2:

通过命令行方式:

./a.outFuncID,调用具体打印功能(每个插件导出GetID接口)

思想:

每一个插件要导出三个函数,分别是Print、Help和GetID。

程序启动后,加载所有插件,把它们的导出函数的地址用三个vector分别保存起来。

然后根据用户的输入,进行对应的调用。

插件1源代码,print_world.cpp

#include

usingnamespacestd;

//打印函数定义

extern"C"voidPrint()

{

cout<<"HelloWorld!

"<

}

//帮助函数

extern"C"voidHelp()

{

cout<<"Thisfunctionprints'HelloWorld!

'"<

}

//返回插件功能ID

extern"C"intGetID()

{

return1;

}

插件2源代码,print_china.cpp

#include

usingnamespacestd;

//打印函数定义

extern"C"voidPrint()

{

cout<<"HelloChina!

"<

}

//帮助函数

extern"C"voidHelp()

{

cout<<"Thisfunctionprints'HelloChina!

'"<

}

//返回插件功能ID

extern"C"intGetID()

{

return2;

}

插件文件搜索类的代码与上相同,省略。

测试程序代码,test.cpp

#include

#include

#include

#include

#include"CPluginSeacher.h"

usingnamespacestd;

//打印函数指针类型

typedefvoid(*FUNC_PRINT)();

//帮助函数指针类型

typedefvoid(*FUNC_HELP)();

//获取ID函数的指针类型

typedefint(*FUNC_GETID)();

//主程序,测试代码

intmain(intargc,char*argv[])

{

//存放所有插件的文件名

vectorvstrPluginNames;

//定义插件搜索类对象

CPluginSeacherenumerator;

//获取所有的插件文件名

if(!

enumerator.GetPluginNames(vstrPluginNames))

{

cout<<"GetPluginNameserror"<

return0;

}

intpluginCount=0;

vectorvecPrint;

vectorvecHelp;

vectorvecGetid;

//遍历文件名数组,依次打开并获取导出函数地址

for(inti=0;i

{

//打开动态链接库文件

void*handle=dlopen(vstrPluginNames[i].c_str(),RTLD_LAZY);

if(handle==0)

{

cout<<"dlopenerror"<

return0;

}

//获取打印函数地址

vecPrint.push_back((FUNC_PRINT)dlsym(handle,"Print"));

//获取帮助印函数地址

vecHelp.push_back((FUNC_HELP)dlsym(handle,"Help"));

//获取ID函数地址

vecGetid.push_back((FUNC_GETID)dlsym(handle,"GetID"));

++pluginCount;

}

//获取用户输入的参数

if(argc>1){

char*param=argv[1];

if(!

strcmp(param,"help"))//用户输入的是help

{

//循环,显示所有插件的功能ID和帮助信息

for(inti=0;i

{

cout<

";//输出ID

vecHelp[i]();//调用帮助信息函数

}

}

else//用户可能输入的是功能ID

{

intid=atoi(param);

//循环,找出该功能

for(inti=0;i

if(vecGetid[i]()==id)//找到了

vecPrint[i]();//调用其打印函数

}

}

return0;

}

先编译测试程序

编译插件1

编译插件2

将两个插件放入plugin目录

测试帮助信息

调用功能1

调用功能2

⏹版本4要求:

⏹在版本3中,插件导出了Print、GetID、Help三个函数,主程序需要使用多个容器分别保存这些函数地址

⏹在复杂的业务逻辑中,导出的函数可能更多,若还按照版本3的方式,代码维护性不佳

⏹将三个导出函数都放在一个类中,让插件外部获取该类的对象

思想:

定义一个插件接口类,所有插件类继承自这个接口类,并覆盖其中的三个方法,然后动态链接库的导出函数,返回类型为父类指针类型,创建一个插件类对象,返回其指针即可。

插件接口类代码,CPluginInterface.h

#ifndefCPLUGININTERFACE_H_

#defineCPLUGININTERFACE_H_

classCPluginInterface

{

public:

virtualvoidPrint(){};

virtualvoidHelp(){};

virtualintGetID(){return0;};

CPluginInterface(){};

~CPluginInterface(){};

};

#endif

插件1代码,print_world.cpp

#include

#include"CPluginInterface.h"

usingnamespacestd;

classPlugin:

publicCPluginInterface{

public:

Plugin()

{

}

virtualvoidPrint()

{

cout<<"HelloWorld!

"<

}

virtualvoidHelp()

{

cout<<"Thisfunctionprints'HelloWorld!

'"<

}

virtualintGetID()

{

return1;

}

};

//获取插件接口对象

extern"C"CPluginInterface*getInterface()

{

staticPluginplugin;

return&plugin;

}

插件2代码,print_china.cpp

#include

#include"CPluginInterface.h"

usingnamespacestd;

classPlugin:

publicCPluginInterface{

public:

Plugin()

{

}

virtualvoidPrint()

{

cout<<"HelloChina!

"<

}

virtualvoidHelp()

{

cout<<"Thisfunctionprints'HelloChina!

'"<

}

virtualintGetID()

{

return2;

}

};

//获取插件接口对象

extern"C"CPluginInterface*getInterface()

{

staticPluginplugin;

return&plugin;

}

插件文件搜索类的代码与上相同,省略。

测试程序代码,test.cpp

#include

#include

#include

#include

#include"CPluginSeacher.h"

#include"CPluginInterface.h"

usingnamespacestd;

//导出函数的指针类型

typedefCPluginInterface*(*FUNC_GETINTERFACE)();

//主程序,测试代码

intmain(intargc,char*argv[])

{

//存放所有插件的文件名

vectorvstrPluginNames;

//定义插件搜索类对象

CPluginSeacherenumerator;

//获取所有的插件文件名

if(!

enumerator.GetPluginNames(vstrPluginNames))

{

cout<<"GetPluginNameserror"<

return0;

}

intpluginCount=0;

vectorvecPluginIfs;

//遍历文件名数组,依次打开并获取导出的接口对象

for(inti=0;i

{

//打开动态链接库文件

void*handle=dlopen(vstrPluginNames[i].c_str(),RTLD_LAZY);

if(handle==0)

{

cout<<"dlopenerror"<

return0;

}

//获取导出的接口对象指针

FUNC_GETINTERFACEfunc=(FUNC_GETINTERFACE)dlsym(handle,"getInterface");

//获取接口对象指针

CPluginInterface*pInterface=func();

//指针存到数组

vecPluginIfs.push_back(pInterface);

++pluginCount;

}

//获取用户输入的参数

if(argc>1){

char*param=argv[1];

if(!

strcmp(param,"help"))//用户输入的是help

{

//循环,显示所有插件的功能ID和帮助信息

for(inti=0;i

{

cout<GetID()<<":

";//调用输出ID

vecPluginIfs[i]->Help();//调用帮助信息函数

}

}

else//用户可能输入的是功能ID

{

intid=atoi(param);

//循环,找出该功能

for(inti=0;i

if(vecPluginIfs[i]->GetID()==id)//找到了

vecPluginIfs[i]->Print();//调用其打印函数

}

}

return0;

}

先编译测试程序

编译插件1和2

把插件放入plugin目录

测试帮助函数

测试插件1的功能

测试插件2的功能

六、实验步骤:

PPT上的4个版本程序

七、总结及心得体会:

经过本次实验,我学习了Linux动态链接库的编写和使用,学习了插件框架的基本设计方法。

八、对本实验过程及方法、手段的改进建议:

报告评分:

指导教师签字:

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1