skynet-skynet_module解析

skynet-skynet_module解析

  • Makefile中的module相关
  • skynet_module.h
  • skynet_module.c
    • skynet_context:
    • skynet_dl_create:
    • skynet_dl_init:
    • skynet_dl_release:
    • skynet_dl_signal:
    • struct skynet_module:
    • skynet_module_insert:
    • skynet_module_query:
    • skynet_module_init:
    • struct modules:
    • _try_open:
    • _query:
    • get_api:
    • open_sym:
  • 设计优势

Makefile中的module相关

源码:

define CSERVICE_TEMP
  $$(CSERVICE_PATH)/$(1).so : service-src/service_$(1).c | $$(CSERVICE_PATH)
	$$(CC) $$(CFLAGS) $$(SHARED) $$< -o $$@ -Iskynet-src
endef

解析:
这部分用来生成一个名为 ( 1 ) . s o 的 动 态 链 接 库 文 件 , 其 中 (1).so 的动态链接库文件,其中 (1).so(1) 是一个占位符,表示模块名。而模块的源文件是以 service_$(1).c 的形式命名的,意味着在 skynet 框架中定义 C 模块时,建议使用 service_ 作为文件名的前缀,以便于在 Makefile 中进行统一的编译和链接处理

skynet_module.h

skynet_module.h 中定义了 skynet 框架中用于管理模块的相关结构体和函数声明,框架可以灵活地扩展功能,实现高度的模块化。通过这种设计,可以更方便地将新的功能模块集成到 skynet 框架中,同时保证了模块之间的独立性和可管理性

源码:

#ifndef SKYNET_MODULE_H
#define SKYNET_MODULE_H

struct skynet_context;

typedef void * (*skynet_dl_create)(void);
typedef int (*skynet_dl_init)(void * inst, struct skynet_context *, const char * parm);
typedef void (*skynet_dl_release)(void * inst);
typedef void (*skynet_dl_signal)(void * inst, int signal);

struct skynet_module {
	const char * name;
	void * module;
	skynet_dl_create create;
	skynet_dl_init init;
	skynet_dl_release release;
	skynet_dl_signal signal;
};

void skynet_module_insert(struct skynet_module *mod);
struct skynet_module * skynet_module_query(const char * name);
void * skynet_module_instance_create(struct skynet_module *);
int skynet_module_instance_init(struct skynet_module *, void * inst, struct skynet_context *ctx, const char * parm);
void skynet_module_instance_release(struct skynet_module *, void *inst);
void skynet_module_instance_signal(struct skynet_module *, void *inst, int signal);

void skynet_module_init(const char *path);

#endif

skynet_module.c

skynet_module.c 定义了模块管理器,负责动态加载和管理skynet框架中的模块

源码:

#include "skynet.h"

#include "skynet_module.h"
#include "spinlock.h"

#include <assert.h>
#include <string.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>

#define MAX_MODULE_TYPE 32

struct modules {
	int count;
	struct spinlock lock;
	const char * path;
	struct skynet_module m[MAX_MODULE_TYPE];
};

static struct modules * M = NULL;

static void *
_try_open(struct modules *m, const char * name) {
	const char *l;
	const char * path = m->path;
	size_t path_size = strlen(path);
	size_t name_size = strlen(name);

	int sz = path_size + name_size;
	//search path
	void * dl = NULL;
	char tmp[sz];
	do
	{
		memset(tmp,0,sz);
		while (*path == ';') path++;
		if (*path == '\0') break;
		l = strchr(path, ';');
		if (l == NULL) l = path + strlen(path);
		int len = l - path;
		int i;
		for (i=0;path[i]!='?' && i < len ;i++) {
			tmp[i] = path[i];
		}
		memcpy(tmp+i,name,name_size);
		if (path[i] == '?') {
			strncpy(tmp+i+name_size,path+i+1,len - i - 1);
		} else {
			fprintf(stderr,"Invalid C service path\n");
			exit(1);
		}
		dl = dlopen(tmp, RTLD_NOW | RTLD_GLOBAL);
		path = l;
	}while(dl == NULL);

	if (dl == NULL) {
		fprintf(stderr, "try open %s failed : %s\n",name,dlerror());
	}

	return dl;
}

static struct skynet_module * 
_query(const char * name) {
	int i;
	for (i=0;i<M->count;i++) {
		if (strcmp(M->m[i].name,name)==0) {
			return &M->m[i];
		}
	}
	return NULL;
}

static void *
get_api(struct skynet_module *mod, const char *api_name) {
	size_t name_size = strlen(mod->name);
	size_t api_size = strlen(api_name);
	char tmp[name_size + api_size + 1];
	memcpy(tmp, mod->name, name_size);
	memcpy(tmp+name_size, api_name, api_size+1);
	char *ptr = strrchr(tmp, '.');
	if (ptr == NULL) {
		ptr = tmp;
	} else {
		ptr = ptr + 1;
	}
	return dlsym(mod->module, ptr);
}

static int
open_sym(struct skynet_module *mod) {
	mod->create = get_api(mod, "_create");
	mod->init = get_api(mod, "_init");
	mod->release = get_api(mod, "_release");
	mod->signal = get_api(mod, "_signal");

	return mod->init == NULL;
}

struct skynet_module * 
skynet_module_query(const char * name) {
	struct skynet_module * result = _query(name);
	if (result)
		return result;

	SPIN_LOCK(M)

	result = _query(name); // double check

	if (result == NULL && M->count < MAX_MODULE_TYPE) {
		int index = M->count;
		void * dl = _try_open(M,name);
		if (dl) {
			M->m[index].name = name;
			M->m[index].module = dl;

			if (open_sym(&M->m[index]) == 0) {
				M->m[index].name = skynet_strdup(name);
				M->count ++;
				result = &M->m[index];
			}
		}
	}

	SPIN_UNLOCK(M)

	return result;
}

void 
skynet_module_insert(struct skynet_module *mod) {
	SPIN_LOCK(M)

	struct skynet_module * m = _query(mod->name);
	assert(m == NULL && M->count < MAX_MODULE_TYPE);
	int index = M->count;
	M->m[index] = *mod;
	++M->count;

	SPIN_UNLOCK(M)
}

void * 
skynet_module_instance_create(struct skynet_module *m) {
	if (m->create) {
		return m->create();
	} else {
		return (void *)(intptr_t)(~0);
	}
}

int
skynet_module_instance_init(struct skynet_module *m, void * inst, struct skynet_context *ctx, const char * parm) {
	return m->init(inst, ctx, parm);
}

void 
skynet_module_instance_release(struct skynet_module *m, void *inst) {
	if (m->release) {
		m->release(inst);
	}
}

void
skynet_module_instance_signal(struct skynet_module *m, void *inst, int signal) {
	if (m->signal) {
		m->signal(inst, signal);
	}
}

void 
skynet_module_init(const char *path) {
	struct modules *m = skynet_malloc(sizeof(*m));
	m->count = 0;
	m->path = skynet_strdup(path);

	SPIN_INIT(m)

	M = m;
}

skynet_context:

其中skynet_context的定义如下,struct skynet_context结构体用于表示一个skynet服务的上下文或环境。其包含了该服务的各种属性和状态信息,并提供了方法来管理和控制服务的行为

struct skynet_context {
	void * instance;
	struct skynet_module * mod;
	void * cb_ud;
	skynet_cb cb;
	struct message_queue *queue;
	ATOM_POINTER logfile;
	uint64_t cpu_cost;	// in microsec
	uint64_t cpu_start;	// in microsec
	char result[32];
	uint32_t handle;
	int session_id;
	ATOM_INT ref;
	int message_count;
	bool init;
	bool endless;
	bool profile;

	CHECKCALLING_DECL
};

void *instance: 该字段通常用于存储与该skynet服务实例相关的数据或指针。

struct skynet_module *mod: 指向skynet模块的指针,用于与该服务相关联的模块管理。

void *cb_ud: 回调函数的用户数据,用于回调函数与服务的交互。

skynet_cb cb: 回调函数,用于处理服务接收到的消息或事件。

struct message_queue *queue: 消息队列指针,用于管理服务接收到的消息。

ATOM_POINTER logfile: 用于记录日志的原子指针。

uint64_t cpu_cost: 服务运行时的CPU消耗。

uint64_t cpu_start: 服务开始运行时的CPU时间。

char result[32]: 存储服务执行结果的缓冲区。

uint32_t handle: 服务的句柄,用于标识唯一的服务实例。

int session_id: 会话ID,用于标识与服务相关的会话。

ATOM_INT ref: 引用计数,用于管理服务的生命周期。

int message_count: 当前服务接收到的消息数量。

bool init: 标志位,表示服务是否已初始化。

bool endless: 标志位,表示服务是否是无限循环执行的。

bool profile: 标志位,表示是否开启性能分析。

skynet_dl_create:

  • 调用模块的 create 函数创建模块的一个实例

skynet_dl_init:

  • 调用模块的init初始化模块实例。参数包括实例对象指针、actor 上下文指针以及初始化参数

skynet_dl_release:

  • 调用模块的release释放实例对象占用的资源

skynet_dl_signal:

  • 调用模块的signal向模块实例发送信号。用于通知模块实例处理事件响应

struct skynet_module:

  • 表示一个动态加载的actor模块
  • 包含特定模块函数的函数指针 (create, init, release, signal)
  • 存储模块的名称和加载的共享库的句柄

skynet_module_insert:

  • 用于将一个模块插入到 skynet 框架中进行管理。

skynet_module_query:

  • 从集合中按名称检索模块,返回相应的模块结构体指针
  • 如果未找到,则尝试使用 _try_open 加载模块,如果成功则将其添加到集合中

skynet_module_init:

  • 用于初始化模块(M),可以指定模块所在的路径

struct modules:

这个结构体用于存储模块的信息,包括模块数量、模块路径以及模块数组。使用自旋锁来保护模块数据的并发访问

  • 管理一组已加载的模块。
  • 使用自旋锁保证线程安全。
  • 包含 skynet_module 结构的数组 (m)。

_try_open:

  • 尝试从各个目录 (path) 加载一个模块 (name)
  • 通过将目录路径中的 ? 替换为模块名称构建完整路径
  • 使用 dlopen 加载模块

_query:

  • 在已加载的模块集合 (M) 中按名称搜索模块

get_api:

  • 在模块 (mod) 中构建函数名 (api_name) 并使用dlsym获取其地址

open_sym:

  • 通过使用 get_api获取函数地址初始化模块的函数指针 (create, init, release, signal)

设计优势

  1. 模块化设计: 通过将模块的创建、初始化、释放等功能封装在模块管理器中,实现了模块化设计,提高了代码的可维护性和可扩展性

  2. 并发安全: 使用自旋锁保护模块数据的并发访问,确保了在多线程环境下的安全性

  3. 支持动态链接和静态链接: 既支持动态链接的模块(通过dlopen加载),也支持静态链接的模块(通过skynet_module_insert手动插入)

  4. 易用性: 对外提供简洁的接口,使得使用者能够方便地加载、查询和操作模块

  • 28
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 《Skynet框架教程-非常详细.pdf》是一本关于Skynet框架的教程,它提供了关于Skynet框架的全面和详细的介绍。 该教程首先介绍了Skynet框架的背景和起源,以及它的特点和优势。Skynet是一个高度可扩展的分布式服务框架,具有高性能和低延迟的特点。它采用了基于actor模型的并发编程模型,并提供了丰富的工具和库来帮助开发者构建和管理分布式应用。 教程的下一部分介绍了Skynet框架的基本概念和架构。它解释了Skynet节点、服务和消息传递等核心概念,并提供了示例代码来说明这些概念的使用方法。读者可以通过这一部分了解Skynet框架的基本原理和用法。 接下来的章节详细介绍了Skynet框架的各个组件和功能。其中包括服务注册与发现、负载均衡、容错机制、监控和调试等方面。每个组件和功能都有详细的说明和示例代码,读者可以通过实践来学习和理解。 教程的最后一部分是一些实际应用案例的介绍。这些案例涵盖了不同领域和规模的应用,包括游戏服务器、在线教育平台、电子商务网站等。每个案例都详细介绍了Skynet框架在该应用中的具体应用和实现过程,对于读者来说是一个很好的参考和借鉴资料。 总之,《Skynet框架教程-非常详细.pdf》是一本很好的Skynet框架学习资料,它提供了全面而详细的内容,涵盖了Skynet框架的各个方面。无论是初学者还是有一定经验的开发者,都可以通过这本教程来学习和掌握Skynet框架的使用和开发技巧。 ### 回答2: 《Skynet框架教程-非常详细.pdf》是一本关于Skynet框架的详细教程文档,其中包含了关于Skynet框架的基本概念、核心功能、使用方法等内容。 Skynet框架是一个高性能、轻量级的分布式服务框架,适用于开发网络游戏、实时通信等高并发场景。该框架基于事件驱动模型,通过异步消息传递和多线程技术实现高并发处理能力。 在《Skynet框架教程-非常详细.pdf》中,首先介绍了Skynet框架的背景与发展历程,帮助读者了解该框架的起源和应用领域。接着详细介绍了Skynet框架的核心架构,包括节点管理、服务管理、消息传递等模块的设计与实现原理。 教程还详细介绍了Skynet框架的安装和配置,包括环境准备、编译与安装等步骤。然后,通过一系列实际案例演示了如何使用Skynet框架进行开发,包括创建节点、注册服务、消息处理、资源管理等方面的内容。 此外,教程还介绍了Skynet框架的调试和优化技巧,包括日志查看、性能测试工具的使用等方面的内容。最后,给出了一些常见问题的解答,帮助读者更好地解决在使用Skynet框架过程中遇到的困惑。 总的来说,《Skynet框架教程-非常详细.pdf》是一本适合初学者和有一定经验的开发人员的教程,通过阅读该教程可以深入了解Skynet框架的原理和使用方法,从而更好地应用于实际项目中。 ### 回答3: 《Skynet框架教程-非常详细.pdf》是一本非常详细的Skynet框架教程。Skynet框架是一个高性能、高可靠性的分布式服务框架,用于构建可扩展的游戏服务器、物联网平台等分布式应用。 这本教程从Skynet框架的基础知识讲起,介绍了Skynet框架的特点、架构和设计理念。然后详细介绍了Skynet框架的安装和配置,包括环境准备、编译安装和启动流程等。 接下来,教程深入讲解了Skynet框架的核心概念和基本用法,包括服务、消息、协议等。这些内容帮助读者理解Skynet框架的工作原理,并能够快速上手开发。 教程还介绍了Skynet框架的高级特性和扩展功能,如集群部署、负载均衡、动态扩容等。这些内容使读者能够在实际应用中解决复杂的问题,并提升系统的性能和可扩展性。 此外,教程还提供了大量的示例和实战案例,帮助读者将理论应用到实际项目中。通过这些实例,读者可以学习到如何使用Skynet架构建真实的分布式应用,同时也能够了解到Skynet框架的一些最佳实践和常见错误。 综上所述,《Skynet框架教程-非常详细.pdf》是一本非常全面的Skynet框架教程,适合初学者和有一定经验的开发者阅读,对于了解Skynet框架的原理和使用方法都有很大帮助。无论是想要学习Skynet框架的基础知识,还是进一步提升Skynet框架的应用技巧,这本教程都是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值