请选择 进入手机版 | 继续访问电脑版
快捷导航
5 119

使用dlopen动态替换so库&一些想法

李腾杰 于 2017-12-11 17:39 发表在 [头脑风暴] [复制链接]
本帖最后由 李腾杰 于 2017-12-11 17:38 编辑

经过上次的测试 发现程序需要重启才能使完成so库替换
之后了解到linux下的动态库函数,查阅资料,做了如下测试

首先将上次的test函数修改成使用库函数
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <string.h>
  4. #include <dlfcn.h>
  5. //动态链接库路径
  6. #define LIB_CACULATE_PATH "./libtest.so"

  7. typedef void (*CAC_FUNC)();

  8. int main(int argc, char const *argv[])
  9. {
  10.         void *dl_handle;
  11.         char *error;
  12.         CAC_FUNC cac_func = NULL;

  13.                 dl_handle = dlopen(LIB_CACULATE_PATH,RTLD_LAZY);
  14.                 if (!dl_handle)
  15.                 {
  16.                         printf("!!!!%s\n",dlerror());
  17.                         return 0;
  18.                 }
  19.         loop:
  20.                 *(void **) (&cac_func) = dlsym(dl_handle, "foo");               
  21.                 error = dlerror();
  22.                 if (error != NULL)
  23.                 {
  24.                         printf("!!!%s\n",error);
  25.                         return 0;
  26.                 }
  27.                 (*cac_func)();

  28.                 sleep(1);
  29.                 goto loop;
  30.         dlclose(dl_handle);
  31.         return 0;
  32. }
复制代码
先打开so文件->再去循环读取文件中的函数->调用so中的函数

之后进行编译
  1. gcc -rdynamic -o test test.c -ldl
复制代码
运行

在运行的过程中
使用“cp”指令测试,程序崩溃

使用“rm+cp”,“mv+cp”分别测试,
测试结果为程序未改变,仍然调用为old.c中的文件,重启为调用new.c
说明,so库更改后,需要重新打开

所以将dlopen(),dlclose()函数放入循环中,
  1. int main(int argc, char const *argv[])
  2. {
  3.         void *dl_handle;
  4.         char *error;
  5.         CAC_FUNC cac_func = NULL;

  6.         loop:
  7.                 dl_handle = dlopen(LIB_CACULATE_PATH,RTLD_LAZY);
  8.                 if (!dl_handle)
  9.                 {
  10.                         printf("!!!!%s\n",dlerror());
  11.                 }

  12.                 *(void **) (&cac_func) = dlsym(dl_handle, "foo");               
  13.                 error = dlerror();
  14.                 if (error != NULL)
  15.                 {
  16.                         printf("!!!%s\n",error);
  17.                 }
  18.                 (*cac_func)();

  19.                 sleep(1);
  20.                 goto loop;
  21.         dlclose(dl_handle);
  22.         return 0;
  23. }
复制代码


但在运行时发现,如果循环dlopen时,执行“rm”或“mv”操作,程序会停止运行


所以dlopen()与“rm”/“mv”操作需要阻塞


所以更新一部分想法如下:
将服务器的主要功能封装一个入口函数,有一个独立的更新程序(更新端),可以调用这个主功能函数(主服端)
更新端:
1.检查更新(版本号/文件传输)
2.需要更新->文件传输(到根据 版本号 建立文件夹中)
3.将新文件夹下的文件,编译生成新的动态链接库.so文件
4.替换so文件,旧so文件可删除/保留
5.重新打开so文件,结束原来的主服端,重新调用主要功能函数(主服端),重新读取so库中函数

这种想法,相当于更新后,把整个程序重启改成,程序不重启的情况下,将so重新打开,再将一部分函数(主要功能)重启

鉴于文件传输,现在只能传输  .c  .h  等文本文件,".so"文件的传输效果未知,所以可将源代码文件传输后,再编译,生成so库将源代码删除。
另:可根据版本号储存so文件,便于管理

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
Connecting & Messaging from Any.

共 5 个关于本帖的回复 最后回复于 2017-12-12 09:39

chinmel 版主 发表于 2017-12-11 22:05:53 from Mobile | 显示全部楼层
这个思路感觉可以。我提供进一步的信息,现在服务器,全部都是dlopen来做的。那么,其实只需要有一个update程序,能够在后台监听到更新事件发生,随后控制服务器程序暂停运行,或是卸载原来dlopen的so模块,接着,执行更新替换,完毕后,重新载入,继续运行。
Connecting & Messaging from Any.
举报 使用道具
chinmel 版主 发表于 2017-12-11 22:11:06 from Mobile | 显示全部楼层
因为涉及到多进程配合,下一步,可以看看多进程通信,重点放在unix domain socket上。
Connecting & Messaging from Any.
举报 使用道具
李腾杰 中级会员 发表于 2017-12-12 08:46:24 | 显示全部楼层
chinmel 发表于 2017-12-11 22:05
这个思路感觉可以。我提供进一步的信息,现在服务器,全部都是dlopen来做的。那么,其实只需要有一个update ...

我觉得,在程序更新的时候不需要暂停再去更新,因为在替换的过程中,即使更改了so文件,如果不close,他不会释放原来的so,那么是不是可以先执行替换操作完成后,再去卸载so,再去重新装载so库文件,即更新替换与服务器程序并行,之后重新装载so库文件
Connecting & Messaging from Any.
举报 使用道具
chinmel 版主 发表于 2017-12-12 09:08:19 | 显示全部楼层
李腾杰 发表于 2017-12-12 08:46
我觉得,在程序更新的时候不需要暂停再去更新,因为在替换的过程中,即使更改了so文件,如果不close,他 ...

只要不出错 随你怎么做
Connecting & Messaging from Any.
举报 使用道具
李腾杰 中级会员 发表于 2017-12-12 09:39:19 | 显示全部楼层
chinmel 发表于 2017-12-12 09:08
只要不出错 随你怎么做

666
Connecting & Messaging from Any.
举报 使用道具
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

推荐板块

精彩推荐

热门排行

明星用户

手机版|小黑屋|AnyMSG ( ©AnyMSG 2009 - 2017 · ICP备16009991号 )

GMT+8, 2019-2-16 20:02