Linux的so组件设计框架及逻辑

Posted lida2003

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux的so组件设计框架及逻辑相关的知识,希望对你有一定的参考价值。

Linux的so组件设计框架及逻辑

组件这个名词在百度上的定义:组件(Component)是对数据和方法的简单封装

这里不再赘述概念和定义,也不再过多纠结很多技术问题或者讨论。我们就实际组件应用关注的焦点和思考,做一个回顾,并整理Linux的so组件设计框架及逻辑。

1. 组件关注点

1.1 组件定义关注点

  1. 组件属性
  2. 组件方法

1.2 组件业务关注点

  1. 支持多实例(线程安全)
  2. 无缝升级(无业务中断)
  3. 支持负荷分担(业务动态迁移)
  4. 支持性能监测
  5. 支持安全策略
  6. 支持可配置(所有参数调优)
  7. 支持优雅退出功能

2. so特性

从库的角度,大体分为静态链接库和动态链接库两大类。so就是linux下动态链接库的后缀。其特性可参考度娘

  1. 扩展了应用程序的特性;
  2. 可以用许多种编程语言来编写;
  3. 简化了软件项目的管理;
  4. 有助于节省内存;
  5. 有助于资源共享;
  6. 有助于应用程序的本地化;
  7. 有助于解决平台差异;
  8. 可以用于一些特殊的目的;

3. so组件设计逻辑

这里以Linux系统为例,但是Windows同样适用(可能代码上稍有差异)。

我们为了解决组件的关注点,应用了动态链接库的特性,从逻辑层面可以解决业务需求。

so动态链接库:

  1. 代码段共享,节省内存;
  2. 数据段每个进程拥有各自的私有数据副本;
  3. 组件方法提供了天然的API接口设计理念,反向要求设计者具备更高的业务抽象和解耦;
  4. 便于版本及项目管理;
  5. 多语言开发平台以及平台差异的天然兼容性;
  6. 析构和构造函数有助于组件的自身动态维护;

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组件设计框架及逻辑的主要内容,如果未能解决你的问题,请参考以下文章

设计模式 -- 装饰者模式

Netty核心组件及基础服务构建

MapReduce框架结构及代码示例

Vue CLI 3结合Lerna进行UI框架设计

前端插件机制的设计理念

前端插件机制的设计理念