skynet1.0阅读笔记_skynet的启动


首先看skynet的启动,函数入口在 skynet_main.c 的main(),其中最重要的是:

        skynet_start(&config);

在skynet_start中做了两个启动:

        //启动了snlau服务,然后加载launch服务
        bootstrap(ctx, config->bootstrap);
        //创建monitor,timer,socket,worker线程等
        start(config->thread);


下面我们逐步跟进函数

1

2

3

4

5

6

7

static void

bootstrap(struct skynet_context * logger, const char * cmdline) {

    ...

    sscanf(cmdline, "%s %s", name, args);

    struct skynet_context *ctx = skynet_context_new(name, args);

    ...

}

这里的cmdline就是 config配置里面的bootstrap那行,默认是为 "snlua bootstrap"


所以实际执行的是 skynet_context_new("snlua","bootstrap")
这里的skynet_context_new是很重要的一个函数,skynet每个lua服务创建,都是使用它来执行的。

复制代码

    skynet_context_new(const char * name="snlua", const char *param="bootstrap") {
        //查询mod对象是否已存在,不存在就根据name查找文件加载创建
        struct skynet_module * mod = skynet_module_query(name="snlua");
        ...
        //调用mod的create()方法,这里调用了 snlua_create
        void *inst = skynet_module_instance_create(mod);
        //为lua服务new一个skynet_context的c对象
        struct skynet_context * ctx = skynet_malloc(sizeof(*ctx));
        ...
        //为服务的ctx创建一个message_queue
        struct message_queue * queue = ctx->queue = skynet_mq_create(ctx->handle);
        //调用对象的init方法,这里是 snlua_init(snlua_create(),ctx,"bootstrap")
        int r = skynet_module_instance_init(mod, inst, ctx, param);
        if(r==0){        //0表示成功
            //成功以后,把服务的message_queue放入global_queue全局队列中
            skynet_globalmq_push(queue);
        }
    }

复制代码

就是说,bootstrap的启动请求 现在交到service_snlua.c的snlua_init里面了,所以接着我们来看snlua_init的实现

复制代码

    snlua_init(struct snlua *l,struct skynet_context *ctx,args="bootstrap"){
        ...
        //把ctx->cb=_launch, ctx->cb是worker线程取出skynet_message时的处理函数
        skynet_callback(ctx, l , _launch);
        //查询自己的handle id
        const char * self = skynet_command(ctx, "REG", NULL);
        uint32_t handle_id = strtoul(self+1, NULL, 16);
        ...
        memcpy(tmp, args, sz);
        // it must be first message ,然后在这里立即投递第一个请求
        skynet_send(ctx, ... , tmp="bootstrap", sz);
        ...
    }

复制代码

 

这里需要注意的是,skynet_command这里,实际上通过遍历查找,最终调用了cmd_reg,由于传入的param是NULL,实际是

     skynet_command(ctx, "REG", NULL){
        sprintf(context->result, ":%x", context->handle);
        return context->result;
     }

//返回的是自己的ctx的handle id.

也就是下面的skynet_send:

        skynet_send(ctx, ... , tmp="bootstrap", sz);

是往自己的队列中投递了一个消息,worker线程拿到这个消息后,根据ctx->cb,调用callback函数: _launch

跟进 _launch:

复制代码

    _launch(..., const void* msg="bootstrap"){
        //把context->cb设为NULL了
        skynet_callback(context, NULL, NULL);
        //_init这里面实际上就是找到要加载的lua文件,然后加载到lua虚拟机中
        //在这里就是把 bootstrap.lua文件加在进来
        _init(l, context, msg, sz);
        ...
    }

复制代码

那我们来看看 bootstrap.lua 这个文件

复制代码

local skynet = require "skynet"
local harbor = require "skynet.harbor"
require "skynet.manager"    -- import skynet.launch, ...
local memory = require "memory"

skynet.start(function()
        ...
        -- 这里面,使用skynet.newservice 启动了很多个服务

    local launcher = assert(skynet.launch("snlua","launcher"))
    skynet.name(".launcher", launcher)

        ...

    if harbor_id == 0 then
        local ok, slave = pcall(skynet.newservice, "cdummy")
        skynet.name(".cslave", slave)
    else
        local ok, slave = pcall(skynet.newservice, "cslave")
        skynet.name(".cslave", slave)
    end
        ...

    if standalone then
        local datacenter = skynet.newservice "datacenterd"
        skynet.name("DATACENTER", datacenter)
    end
        ...
end)

复制代码

这里有两点要注意:
1. skynet.start 的function里面,用snlua启动了launcher服务,并用skynet.name把自己注册名字为".launcher"的服务
".launcher" 的调用 skynet.call(".launcher",...)
在后面将经常看到。".launcher"服务就是在这里注册的。
以.开头的名字,是表示这个服务只在当前skynet节点下有效,如果不带点,需要支持跨节点的额外开销,没必要都会带上它。

2.skynet.start 函数

复制代码

    function skynet.start(start_func)
        //把回调函数注册为 skynet.dispatch_message
        c.callback(skynet.dispatch_message)
        //调用 skynet.init_service 调用了外面定义的 function 进行启动
        skynet.timeout(0, function()
            skynet.init_service(start_func)
        end)
    end

复制代码

到这里,就能明白,通过skynet_context_new 中的 snlua_init 和
_launch,skynet把请求的处理权从 c交到了 lua手上。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值