作者:shihuaping0918@163.com,转载请注明作者
在第5篇和第6篇已经分析过消息的发送和消息的处理,但是没有谈到消息回调函数的注册,还有消息回调的详细过程。第9篇已经讲了一部分消息的回调处理。
skynet中的回调对C服务和对LUA服务的注册机制是不同的,C服务的回调可以直接挂载。但是lua服务不行,它必须经过一次中转。这个在第9篇中谈到过,但是第9篇主要是介绍lua c api的协议的。
本篇分为两部分,第一部分介绍C服务的回调。第二部分介绍lua服务的注册与回调。第一部分比较简短,第二部分会比较长。
第一部分:C服务的回调
C服务的回调非常简单,直接把函数挂上去就可以。我们以skynet中的日志服务为例说明一下这个过程。
skynet中的日志服务在skynet/service-src/service-logger.c中。在第一篇介绍模块(服务)的时候就提到过,每个服务有create/init/release/signal四类函数。而logger服务也不例外,回调的挂载就是在init函数中进行的。
int
logger_init(struct logger * inst, struct skynet_context *ctx, const char * parm) {
if (parm) {
inst->handle = fopen(parm,"w");
if (inst->handle == NULL) {
return 1;
}
inst->filename = skynet_malloc(strlen(parm)+1);
strcpy(inst->filename, parm);
inst->close = 1;
} else {
inst->handle = stdout;
}
if (inst->handle) {
skynet_callback(ctx, inst, logger_cb); //注册回调
skynet_command(ctx, "REG", ".logger"); //注册服务
return 0;
}
return 1;
}
C服务注册回调用的是skynet_callback函数,这个函数只有2行。
void
skynet_callback(struct skynet_context * context, void *ud, skynet_cb cb) {
context->cb = cb; //回调函数挂载
context->cb_ud = ud; //这个是个辅助指针
}
C服务的回调挂载/注册就是这么简单。最后再来看一下这个回调是在哪里被调用的,是被怎么调用的。以便形成一个比较系统的概念,而不是盲人摸象。
回调的调用是在dispatch_message函数中进行的,这个函数前面已经分析过了,只是没有讲回调的注册过程。
static void
dispatch_message(struct skynet_context *ctx, struct skynet_message *msg) {
assert(ctx->init);
CHECKCALLING_BEGIN(ctx)
pthread_setspecific(G_NODE.handle_key, (void *)(uintptr_t)(ctx->handle));
int type = msg->sz >> MESSAGE_TYPE_SHIFT;
size_t sz = msg->sz & MESSAGE_TYPE_MASK;
if (ctx->logfile) {
skynet_log_output(ctx->logfile, msg