Linux的so组件设计框架及逻辑
Posted lida2003
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux的so组件设计框架及逻辑相关的知识,希望对你有一定的参考价值。
Linux的so组件设计框架及逻辑
组件这个名词在百度上的定义:组件(Component)是对数据和方法的简单封装
这里不再赘述概念和定义,也不再过多纠结很多技术问题或者讨论。我们就实际组件应用关注的焦点和思考,做一个回顾,并整理Linux的so组件设计框架及逻辑。
1. 组件关注点
1.1 组件定义关注点
- 组件属性
- 组件方法
1.2 组件业务关注点
- 支持多实例(线程安全)
- 无缝升级(无业务中断)
- 支持负荷分担(业务动态迁移)
- 支持性能监测
- 支持安全策略
- 支持可配置(所有参数调优)
- 支持优雅退出功能
2. so特性
从库的角度,大体分为静态链接库和动态链接库两大类。so就是linux下动态链接库的后缀。其特性可参考度娘:
- 扩展了应用程序的特性;
- 可以用许多种编程语言来编写;
- 简化了软件项目的管理;
- 有助于节省内存;
- 有助于资源共享;
- 有助于应用程序的本地化;
- 有助于解决平台差异;
- 可以用于一些特殊的目的;
3. so组件设计逻辑
这里以Linux系统为例,但是Windows同样适用(可能代码上稍有差异)。
我们为了解决组件的关注点,应用了动态链接库的特性,从逻辑层面可以解决业务需求。
so动态链接库:
- 代码段共享,节省内存;
- 数据段每个进程拥有各自的私有数据副本;
- 组件方法提供了天然的API接口设计理念,反向要求设计者具备更高的业务抽象和解耦;
- 便于版本及项目管理;
- 多语言开发平台以及平台差异的天然兼容性;
- 析构和构造函数有助于组件的自身动态维护;
4. so组件设计框架
通过组件的构造和析构作为组件初始化和去初始化机制,当然为了更好的应对优雅退出及异常场景处理,在构造函数中需要做非常多的业务/异常场景的分析和钩子函数设计。
这里针对构造、析构和接口问题进行框架介绍和范例举例:
4.1 so组件范例
- 构造函数
- 析构函数
- API接口
//so_test.c
#include <stdio.h>
int Myfunc_test(void)
printf("........Myfunc_test in %s........\\n", __FILE__);
return(0);
static void __attribute__((constructor)) Myfunc_init(void)
printf("Myfunc_init in %s\\n", __FILE__);
return;
static void __attribute__((destructor)) Myfunc_fini(void)
printf("Myfunc_fini in %s\\n", __FILE__);
return;
//so_test.h
#ifndef __SO_TEST_HEADER__
#define __SO_TEST_HEADER__
int Myfunc_test(void);
#endif /* __SO_TEST_HEADER__ */
编译方法
$ gcc -fPIC -shared -o libtestsubx.so so_test.c
4.2 so隐式调用范例
#include <stdio.h>
#include "so_test.h"
int main(int argc, char** argv)
printf("so main\\n");
Myfunc_test();
sleep(5);
printf("so main exit\\n");
编译方法
$ gcc -g so_main.c -o so_main -L. -ltestsubx
鉴于隐式调用收到so路径的限制,因此需要更好的管理路径,测试脚本如下
#!/bin/sh
export LD_PRELOAD=$pwdlibtestsubx.so:$LD_PRELOAD
export LD_LIBRARY_PATH=$pwd:$LD_LIBRARY_PATH
./so_main
4.3 so显式调用范例
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <dlfcn.h>
#include "so_test.h"
int main(int argc, char** argv)
void(*pTest)();
char dir[256];
char *path = getcwd(dir, 256);
if ( path == NULL )
printf("Failed get current dir\\n");
return -1;
strcat(path, "/");
strcat(path, "/libtestsubx.so");
printf("Current so is %s\\n", path);
void*pdlHandle = dlopen(path, RTLD_LAZY);
if( pdlHandle == NULL )
printf("Failed load library\\n");
return -1;
char* pszErr = dlerror();
if(pszErr != NULL)
printf("%s\\n", pszErr);
return -1;
pTest = dlsym(pdlHandle, "Myfunc_test");
pszErr = dlerror();
if( pszErr != NULL )
printf("%s\\n", pszErr);
dlclose(pdlHandle);
return -1;
(*pTest)();
dlclose(pdlHandle);
return 0;
编译方法
$ gcc -g so_dlopen.c -o so_dlopen -L. -ldl
5 so组件设计建议
根据实际应用的要求,选择隐式调用和显式调用。通常来说简单设计,隐式调用更加方便和直接。
而从实际要对组件进行“1.2 组件业务关注点”这种复杂考虑,那么建议采用显式调用方法,并针对API进行管理(这里的API是指函数)。更多业务类解耦可以考虑消息API。
在大型项目开发中,需要建立主体程序框架和基于主体程序框架的业务组件设计框架,以便针对业务的组件能够通过各种API进行解耦,独立进行开发、测试。
以上是关于Linux的so组件设计框架及逻辑的主要内容,如果未能解决你的问题,请参考以下文章