Linux下动态链接库技术实现“消息映射表”
linux,C,C++,.SO,动态库加载2016-11-17
题目:
利用动态链接库技术实现具有热插拔能力的“消息映射表”程序。程序在功能上表现为一个计算器程序,主菜单中提示:
Press A:Adding;
Press S: Subtracting
Press M: Multiplying
Press D: Dividing
用户键入A则启动加法子程序,提示用户输入两个操作数,并输出计算结果。用户键入S则启动减法子程序。以此类推。子程序执行完毕之后再回到主菜单状态。
使该程序有热插拔能力是指可以通过配置文件在不改变主程序的前提下动态增加新的菜单项和新的功能(例如增加乘方、开方、指数、对数运算等。)
设计思路:首先,设计并实现程序所需的动态链接库,其次,在主函数中开辟一个线程监控配置文件是否被改变,如果配置文件发生改变则重新读取配置文件中内容。最后,根据用的不同输入加载不同的动态库和函数。根据设计思路,本文从动态库生成、配置文件设计、配置文件监控和动态链接库动态加载四个方面展开介绍。
要想使用动态链接库技术必须要有动态库,因此本节主要介绍linux下动态库的编译与链接。下面以题目中计算器程序为例为大家讲解。文件名为calculate1.c。
#include<stdio.h> intAdd(int x,int y) { int tmp = x + y; printf("%d + %d = %d\n", x,y,tmp); return tmp; } intSub(int x,int y) { int tmp = x - y; printf("%d - %d = %d\n", x,y,tmp); return tmp; } intMultiply(int x,int y) { int tmp = x * y; printf("%d * %d = %d\n", x,y,tmp); return tmp; } intDivigcc -c -fPIC calculate1.c gcc -shared -fPIC calculate1.o -o a.sode(int x,int y) { int tmp = x / y; printf("%d / %d = %d\n", x,y,tmp); return tmp; }
gcc -c -fPIC calculate1.c gcc -shared -fPIC calculate1.o -o a.so
消息 |
菜单项提示 |
所处动态库 |
函数入口 |
A |
Adding |
a.so |
Add |
S |
Subtracting |
a.so |
Sub |
M |
Multiplying |
a.so |
Multiply |
D |
Dividing |
a.so |
Divide |
P |
Power |
b.so |
Pow |
int fd = inotify_init();
其中,每一个 inotify 实例对应一个独立的排序的队列。
文件系统的变化事件被称做 watches 的一个对象管理,每一个 watch 是一个二元组(目标,事件掩码),目标可以是文件或目录,事件掩码表示应用希望关注的 inotify 事件,每一个位对应一个 inotify 事件。Watch 对象通过 watch描述符引用,watches 通过文件或目录的路径名来添加。目录 watches 将返回在该目录下的所有文件上面发生的事件。
下面函数用于添加一个 watch:
int wd = inotify_add_watch(fd, path, mask);
size_t len = read(fd, buf, BUF_LEN);
struct inotify_event {
__s32 wd;/* watch descriptor */
__u32 mask;/* watch mask */
__u32 cookie;/* cookie to synchronize two events */
__u32 len;/* length (including nulls) of name */
char name[0];/* stub for possible name */
};
void* displayInotifyEventThread(void* arg) { int inotifyFd; int wd; int j; int flags; char buf[BUF_LEN]; ssize_t numRead; char*p; struct inotify_event *event; typedefvoid(*pp)(); pp read_config =(pp)arg; inotifyFd = inotify_init(); if(inotifyFd ==-1) { printf("inotify initual failed\n"); } wd = inotify_add_watch(inotifyFd,path,IN_ALL_EVENTS); if(wd ==-1) { printf("inotify_add_watch error\n"); } if(DEBUG) printf("Watching %s using wd %d\n",path,wd); while(1) { numRead = read(inotifyFd,buf,BUF_LEN); if(numRead ==-1) { printf("read error\n"); } if(DEBUG) printf("Read %ldbytes from inotify fd\n",(long)numRead); read_config(); } usleep(10*1000); }
void* readConfig() { int fd; int filecount; char filebuf[4096]={0}; fd = open(path,O_RDONLY); filecount = read(fd,filebuf,4096*sizeof(char)); if(fd !=-1) { int proccount =0; char str[5][50]; MsgMapTable MMT; memset(&MMT,0,sizeof(MMT)); int k =0; for(int i =0; i <5; i++) { memset(str[i],0,50); } for(int i =0;i < filecount;i++) { if(filebuf[i]!= EOF) { if(filebuf[i]!='\n'&& filebuf[i]!=' ') { proccount++; }else{ memcpy(str[k],filebuf+i-proccount,proccount); k++; proccount =0; } if(k >3) { memcpy(MMT.OPMODE,str[0],strlen(str[0])); memcpy(MMT.OPMODEMEAN,str[1],strlen(str[1])); memcpy(MMT.LIBNAME,str[2],strlen(str[2])); memcpy(MMT.FUNNAME,str[3],strlen(str[3])); string key = MMT.OPMODE; msg_map_tables[key]= MMT; //msg_map_tables.insert(map<string,MsgMapTable>::value_type(key,MMT)); for(int i =0; i <5; i++) { memset(str[i],0,50); } if(DEBUG) { cout<<"readConfig:key is "<<key<<"\n"; cout<<msg_map_tables[key].OPMODE<<" "<<msg_map_tables[key].OPMODEMEAN<<" "<<msg_map_tables[key].LIBNAME<<" "<<msg_map_tables[key].FUNNAME<<"\n"; } memset(&MMT,0,sizeof(MMT)); k =0; } } } } }
void*dlopen(constchar*file,int mode);
void*dlsym(void*handle,constchar*name) 功能:根据动态链接库操作句柄与符号,返回符号对应的地址,可以是函数也可以是变量。 参数: handle : dlopen返回的动态链接库句柄 name :符号名称,可为函数名或变量名称
int dlclose(void*handle) 功能:关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载
void searchMap(char* opMode) { char lib_path[20]="./"; map<string ,MsgMapTable>::iterator l_it; l_it=msg_map_tables.find(opMode); if(l_it == msg_map_tables.end()) { printf("opMode is error\n"); return; } if(DEBUG) cout<<"l_it->second.LIBNAME is "<<l_it->second.LIBNAME; strcat(lib_path,l_it->second.LIBNAME); void*lib = dlopen(lib_path, RTLD_LAZY); if(DEBUG) cout<<"\nl_it->second.FUNNAME is "<<l_it->second.FUNNAME; calculate_t calculate =(calculate_t)dlsym(lib, l_it->second.FUNNAME); if(DEBUG) cout<<"\nnum1 = "<<num1<<" num2 = "<<num2<<"\n"; calculate(num1,num2); dlclose(lib); }