您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > 电子科大李老师Linux实验四
电子科技大学实验报告学生姓名:学号:指导教师:李林实验地点:实验时间:Csdn全部资源下载地址:一、实验室名称:Linux环境高级编程实验室二、实验项目名称:插件框架实验三、实验学时:4学时四、实验目的:需要说明为什么要进行本次实验五、实验内容:版本1:开发一个程序,向屏幕打印“HelloWorld”;在不重新编译链接原程序的前提下,将打印的文字改为“HelloChina”思想:将打印函数编译为一个动态链接库文件,然后测试程序用显式调用的方式,加载动态链接库,并调用其中的打印函数。此后要改变输出内容,只需要重新编译动态链接库文件,而无需对测试程序进行修改。动态链接库源文件代码(导出打印函数),print.cpp:#includeiostreamusingnamespacestd;//打印函数定义externCvoidPrint(){coutHelloWorld!endl;}测试程序源代码,test.cpp:#includedlfcn.h#includeiostreamusingnamespacestd;//主程序,测试动态链接库intmain(){//打开动态链接库文件void*handle=dlopen(./libprint.so,RTLD_LAZY);if(handle==0)//打开失败{coutdlopenerrorendl;return0;}//定义一个函数指针类型typedefvoid(*FUNC_PRINT)();//映射打印函数地址FUNC_PRINTdl_print=(FUNC_PRINT)dlsym(handle,Print);if(dl_print==0){coutdlsymerrorendl;return0;}//调用打印函数(dl_print)();//卸载动态链接库dlclose(handle);return0;}先编译测试程序再编译动态链接库运行测试程序,输出HelloWorld修改print.cpp里的输出内容为HelloChina重新编译动态链接库文件之后,再运行测试程序,输出了HelloChina版本2要求:同时要打印“HelloWorld”,打印“HelloChina”,甚至同时打印未来才会增加的其他打印信息打印未来的这些信息,也不能重新编译链接原程序思想:使用插件的思想,将所有的动态链接库文件放置在一个plugin的文件夹中,然后测试程序去遍历该目录,依次打开所有的动态链接库文件,并调用其中的Print函数。另外遍历目录获取动态链接库文件名这个任务,定义一个单独的工具类来实现。第一个动态链接库源代码,print_world.cpp:#includeiostreamusingnamespacestd;//打印函数定义externCvoidPrint(){coutHelloWorld!endl;}第二个动态链接库源代码,print_china.cpp:#includeiostreamusingnamespacestd;//打印函数定义externCvoidPrint(){coutHelloChina!endl;}插件文件搜索类头文件,CPluginSeacher.h:#ifndefCPLUGINSEARCHER_H#defineCPLUGINSEARCHER_H#includevector#includestringusingnamespacestd;//插件搜索类声明classCPluginSeacher{public:CPluginSeacher();virtual~CPluginSeacher();//获取所有的插件文件名boolGetPluginNames(vectorstring&vstrPluginNames);};#endif插件文件搜索类源文件,CPluginSeacher.cpp:#includeCPluginSeacher.h#includedirent.h#includestring.hCPluginSeacher::CPluginSeacher(){}CPluginSeacher::~CPluginSeacher(){}//获取所有的插件文件名boolCPluginSeacher::GetPluginNames(vectorstring&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:#includedlfcn.h#includeiostream#includeCPluginSeacher.husingnamespacestd;//主程序,测试遍历目录,调用所有动态链接库intmain(){//存放所有动态链接库的文件名vectorstringvstrPluginNames;//定义插件搜索类对象CPluginSeacherenumerator;//获取所有的插件文件名if(!enumerator.GetPluginNames(vstrPluginNames)){coutGetPluginNameserrorendl;return0;}//遍历文件名数组,依次打开并调用for(inti=0;ivstrPluginNames.size();i++){//打开动态链接库文件void*handle=dlopen(vstrPluginNames[i].c_str(),RTLD_LAZY);if(handle==0){coutdlopenerrorendl;return0;}//定义一个函数指针类型typedefvoid(*FUNC_PRINT)();//映射打印函数地址FUNC_PRINTdl_print=(FUNC_PRINT)dlsym(handle,Print);if(dl_print==0){coutdlsymerrorendl;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#includeiostreamusingnamespacestd;//打印函数定义externCvoidPrint(){coutHelloWorld!endl;}//帮助函数externCvoidHelp(){coutThisfunctionprints'HelloWorld!'endl;}//返回插件功能IDexternCintGetID(){return1;}插件2源代码,print_china.cpp#includeiostreamusingnamespacestd;//打印函数定义externCvoidPrint(){coutHelloChina!endl;}//帮助函数externCvoidHelp(){coutThisfunctionprints'HelloChina!'endl;}//返回插件功能IDexternCintGetID(){return2;}插件文件搜索类的代码与上相同,省略。。。测试程序代码,test.cpp#includedlfcn.h#includeiostream#includestring.h#includestdlib.h#includeCPluginSeacher.husingnamespacestd;//打印函数指针类型typedefvoid(*FUNC_PRINT)();//帮助函数指针类型typedefvoid(*FUNC_HELP)();//获取ID函数的指针类型typedefint(*FUNC_GETID)();//主程序,测试代码intmain(intargc,char*argv[]){//存放所有插件的文件名vectorstringvstrPluginNames;//定义插件搜索类对象CPluginSeacherenumerator;//获取所有的插件文件名if(!enumerator.GetPluginNames(vstrPluginNames)){coutGetPluginNameserrorendl;return0;}intpluginCount=0;vectorFUNC_PRINTvecPrint;vectorFUNC_HELPvecHelp;vectorFUNC_GETIDvecGetid;//遍历文件名数组,依次打开并获取导出函数地址for(inti=0;ivstrPluginNames.size();i++){//打开动态链接库文件void*handle=dlopen(vstrPluginNames[i].c_str(),RTLD_LAZY);if(handle==0){coutdlopenerrorendl;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(argc1){char*param=argv[1];if(!strcmp(param,help))//用户输入的是help{//循环,显示所有插件的功能ID和帮助信息for(inti=0;ipluginCount;i++){coutvecGetid[i]():;//输出IDvecHelp[i]();//调用帮助信息函数}}else//用户可能输入的是功能ID{intid=atoi(param);//循环,找出该功能for(inti=0;ipluginCount;i++)if(vecGetid[i]()==id)//找到了vecPrint[i]();//调用其打印函数}}return0;}先编译测试程序编译插件1编译插件2将两个插件放入plugin目录测试帮助信息调用功能1调用功能2版本4
本文标题:电子科大李老师Linux实验四
链接地址:https://www.777doc.com/doc-4903715 .html