5-bootstrap服务的启动

新入门skynet系列视频b站网址 https://www.bilibili.com/video/BV19d4y1678X

bootstrap服务的启动

bootstrap实际上也是一个snlua服务。他是我们skynet启动时创建的第二个服务。

void 
skynet_start(struct skynet_config * config) {
	//首先创建日志服务
	struct skynet_context *ctx = skynet_context_new(config->logservice, config->logger);

	skynet_handle_namehandle(skynet_context_handle(ctx), "logger");//给日志服务绑定一个名字
	
    //创建bootstrp服务 注意这里服务并没有完成所有流程 因为工作线程还没有启动 服务的第一个消息只是push进队列了
	bootstrap(ctx, config->bootstrap);//"snlua bootstrap"

	start(config->thread);

	//other code
}

行8就是启动一个bootstrap服务,继续看

static void
bootstrap(struct skynet_context * logger, const char * cmdline) {
	//name是 snlua 
    //arge是 bootstrap
	struct skynet_context *ctx = skynet_context_new(name, args);

}

我们直接开始看bootstrap.lua的执行

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

skynet.start(function()
	local standalone = skynet.getenv "standalone"
	--`skynet.launch(servicename, ...)` 用于启动一个 C 模块的服务。主要意思是 第一个参数是 c 模块的名字 可以是snlua logger 这种
	local launcher = assert(skynet.launch("snlua","launcher"))--snlua的创建分为两步 1.push一个启动消息给自己 2.处理启动消息并执行对应lua文件 属于异步
	skynet.name(".launcher", launcher)

	local harbor_id = tonumber(skynet.getenv "harbor" or 0)
	if harbor_id == 0 then --单节点模式
		assert(standalone ==  nil)
		standalone = true
		skynet.setenv("standalone", "true") --注意这里设置为ture
		
        --skynet.newservice 是启动一个snlua服务,第一个参数是服务对应的lua文件的名字 会阻塞当前协程
		local ok, slave = pcall(skynet.newservice, "cdummy")

		skynet.name(".cslave", slave)

	else -- 非单节点模式
		-- 略
	end

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

	pcall(skynet.newservice,skynet.getenv "start" or "main") --最终启动我们配置的main服务
	
    skynet.exit() --最后自己功成身退
end)

这里我们说一下 单节点模式多节点模式

  • 如果我们的harbor_id配置为0 或者不配置,那么表示我们的skynet运行在单节点模式。也就是skynet节点都是独立的。如果我再启动一个skynet节点,同时也是单节点模式,那么这两个节点相对对方来说,都是外部网络。就像一个玩家主动连接我们的skynet节点一样,我们把玩家当作是外部网络。

  • 如果我们harbor_id配置为大于0的数字,那么一般会启动多个skynet节点,同时每个skynet配置的harbor_id是不同的。这就是说明,这些skynet节点形成了一个网络.当然这种集群模式现在skynet不推荐了。

而我们的课程只讨论单节点模式下的skynet.

接下来我们再一次分析bootstrap服务入口函数的执行过程,直到bootstrap服务自己退出

image-20220906185624270

skynet.exit发送了一个消息给launcher,当然launcher没有任何反应。因为 bootstrap不是通过 skynet.newservice创建的。所以launcher里面是查不到bootstrap服务的,所以不会做进一步处理。

之后skynet.exit通知底层,然后挂起了定时器协程,即coroutine_yield "QUIT",当然也没机会发送启动ok的消息给launcher了。

之后suspend通过这个"QUIT"判断服务要退出,所以把当前运行的定时器协程关闭,同时return,表示 skynet.dispatch_message函数处理完成。

接下来我们简单的看看底层是如何退出服务的。

因为在通知底层退出的时候,我们其实正在bootstrap服务的回调函数中,也即是ctx是被引用的。所以ctx还不会被马上释放。当我们的skynet.dispach_message结束的时候,ctx就没有引用了,此时服务队列会被放进全局队列,之后服务会被标记释放。当工作线程下次取出队列,得到handle,发现通过handle无法找到ctx的时候,就会开始真正释放服务相关的内容了。

posted @ 2022-12-08 15:41  程序员阿钢  阅读(456)  评论(0编辑  收藏  举报