skynet源码分析之skynet_module

skynet_module提供一个模板来实现各种不同类型的c服务,比如,snlua(最常见),logger,gate等。

先说明两个linux系统函数:

// dlopen函数用来获取so库的访问句柄。本质是将so库加载到内存中,并返回一个可以访问该内存块的句柄
void *dlopen(const char *filename, int flags);

//The function dlopen() loads the dynamic shared object (shared library) file named by the null-terminated string filename and returns an opaque "handle" for the loaded object.


// dlsym函数,以dlopen返回的handle为第一个参数,获取so库中名称为symbol的函数指针,通过该指针可以获得so库里的函数地址
void *dlsym(void *handle, const char *symbol);

//The  function  dlsym()  takes a "handle" of a dynamic loaded shared object returned by dlopen(3) along with a
  null-terminated symbol name, and returns the address where that symbol is loaded into memory

skynet_module的结构如下:

struct modules {
    int count;
    struct spinlock lock;
    const char * path;// 用c编写的服务编译后so库路经,不配置默认是./cservice/?.so
    struct skynet_module m[MAX_MODULE_TYPE]; //存放服务模块的数组
};

static struct modules * M = NULL;


struct skynet_module { //单个模块结构
    const char * name; //c服务名称,一般是指c服务的文件名
    void * module; //访问so库的dl句柄,通过dlopen获得该句柄
    skynet_dl_create create; //通过dlsym绑定so库中的xxx_create函数,调用create即调用xxx_create接口
    skynet_dl_init init; //绑定xxx_init接口
    skynet_dl_release release; //绑定xxx_release接口
    skynet_dl_signal signal; //绑定xxx_signal接口
};

 M->path在初始化(skynet_module_init)时赋值,对应配置文件的cpath,不配置默认是./cservice/?.so。

用c编写的服务编译成so库后放在cpath目录下,当创建一个ctx时(skynet_context_new),通过名称在skynet_module里找对应的module(skynet_module_query),如果M->m存有同名称的module,返回即可。

如果第一次创建该名称的服务,先找到该名称对应的so库的路径,然后通过dlopen函数获取so库的访问句柄dl(try_open),再通过dlsym函数获取so库中xxx_create, xxx_init, xxx_release, xxx_signal4个函数地址(open_sym),将这些地址赋值给skynet_module->create, skynet_module->init, skynet_module->release, skynet_module->signal。通常一个c服务需要提供这4个接口,定义这些接口时一定要以服务名称为前缀,通过下划线和函数名称连接起来:

xxx_create:创建ctx过程中调用,通常是申请内存。返回该服务的实例inst,设置ctx->instance=inst,之后init,release,signal都需要用到该实例

xxx_init:创建ctx期间调用,除了初始化,最主要的工作是向ctx注册callback函数(skynet_callback),之后ctx才能正确的处理收到的消息(调用callback函数)

xxx_release:释放ctx时调用(skynet_context_release)

xxx_signal:ctx收到信号时调用

最后将skynet_module保存到M->m里,之后创建同名称ctx就不用获取so库的访问句柄了。

posted on 2018-01-11 21:33  RainRill  阅读(521)  评论(0编辑  收藏  举报

导航