首页 > 其他分享 >5-skynet.newservice创建snlua服务

5-skynet.newservice创建snlua服务

时间:2022-12-08 15:11:09浏览次数:76  
标签:服务 -- db newservice snlua launcher skynet end

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

# skynet.newservice创建snlua服务

之前讲 服务间请求和响应的时候,我们在main服务里启动了一个db服务。看代码

--main.lua
local skynet = require "skynet"

skynet.start(function()--lua服务的入口函数
	
	local db = skynet.newservice("db")--启动一个db服务
	local key = "zhangsan"
	 
	local age = skynet.call(db, "lua", "GET",key) --发送 lua类型 的请求给db服务,然后等待对方回应

	skynet.exit()
	
end)

我们调用 skynet.newservice("db")启动了一个db服务。当我们调用skynet.newservice的时候,当前协程会挂起。他会发送一个请求给 launcher服务,表示请启动一个db服务。launcher服务收到请求后,会启动创建db服务。当db服务启动完成后,会通知launcher服务,此时launcher服务才会发送响应消息给我们的main服务。这个时候,我们skynet.newservice调用才会返回。

image-20220608104640262

关于launcher服务的创建,看这里 launcher的创建 .

我们具体看看 skynet.newservice("db")

function skynet.newservice(name, ...)
	return skynet.call(".launcher", "lua" , "LAUNCH", "snlua", name, ...)
end

这里调用skynet.call 。注意参数 "LAUNCH", "snlua", “db” 。我们再看看launcher服务是怎么处理的。

--launcher.lua
function command.LAUNCH(_, service, ...)--收到服务main 请求创建一个服务db 的消息
	launch_service(service, ...) --此时 service是 "snlua" 
	return NORET --注意这里 NORET 表示 当前协程不用返回响应给main服务
end

skynet.dispatch("lua", function(session, address, cmd , ...) --设置任务函数 f
	cmd = string.upper(cmd)
	local f = command[cmd] --此时cmd是 "LAUNCH"
	if f then
		local ret = f(address, ...)
		if ret ~= NORET then
			skynet.ret(skynet.pack(ret))
		end
	end
end)

继续看 launch_service 函数。实际上这个函数主要是调用了skynet.launch创建了模块为snlua的lua服务。因为skynet.launch函数的特点如下

  • 在当前工作线程下调用 skynet_context_new 创建db服务,并给对应的队列push一个消息
  • 在合适的时机,队列的消息被取出被处理,同时执行服务对应的lua文件

所以当前launcher服务只能等待。 当被创建的db服务的lua文件执行完成初始化后,也就是发送一个完成服务创建的通知给launcher时,launcher才会回应main服务。

local function launch_service(service, ...)
	local param = table.concat({...}, " ")
	local inst = skynet.launch(service, param)-- 此时service是 "snlua"  param 是 "db"
	local session = skynet.context()
	local response = skynet.response() --这个返回一个闭包 
	if inst then --inst是db服务的地址
		services[inst] = service .. " " .. param
		instance[inst] = response
		launch_session[inst] = session
	else
		response(false)
		return
	end
	return inst
end

上面的代码实际上记录了请求者main服务的信息。现在假设db服务的db.lua文件执行完成了初始化。也就是db.lua的skynet.start注册的定时器触发了。还记得吗?这个定时器主要做了两件事 1. 执行启动函数 2.发送服务创建完成的通知给launcher服务。我们看看skynet.start函数。

--skynet.lua
function skynet.init_service(start)
	local function main()
		skynet_require.init_all()
		start() --执行启动函数 start_func
	end
	local ok, err = xpcall(main, traceback)
	if not ok then
		--略
	else
		skynet.send(".launcher","lua", "LAUNCHOK")--任何服务在完成start后 都会发送 LAUNCHOK 消息给 launcher服务
	end
end

function skynet.start(start_func)
	c.callback(skynet.dispatch_message)
	init_thread = skynet.timeout(0, function()
		skynet.init_service(start_func)
		init_thread = nil
	end)
end

注意上面的 行10 代码。我们现在看看launcher收到这个 LAUNCHOK 消息的处理过程。

--每一个lua服务启动完成后(即start_func函数执行完毕 都会发送一个LAUNCHOK 消息给 launcher服务
function command.LAUNCHOK(address) --收到服务db send过来的消息 表示服务db自身已经完成创建
	-- init notice
	local response = instance[address] --address是db服务的地址
	if response then
		response(true, address) -- 发送响应给 之前的 main服务
		instance[address] = nil
		launch_session[address] = nil
	end

	return NORET
end

行4 通过db的地址找到了之前已经准备好的响应闭包。然后在 行6 执行这个闭包。这样launcher就算是真正响应main服务了,虽然这个响应是延迟的。我们可以具体看看这个 闭包。实际上在 行13回应了main服务。相当于告诉main服务,你要的db服务,我已经给你创建好了。

function skynet.response(pack)
	pack = pack or skynet.pack

	local co_session = assert(session_coroutine_id[running_thread], "no session")
	session_coroutine_id[running_thread] = nil --这里不再保存session了 因为下面的response闭包已经保存session了
	local co_address = session_coroutine_address[running_thread]

	local function response(ok, ...)

		local ret
		if unresponse[response] then
			if ok then
				ret = c.send(co_address, skynet.PTYPE_RESPONSE, co_session, pack(...))
			end
			unresponse[response] = nil
			ret = ret ~= nil
		else
			ret = false
		end
		pack = nil
		return ret
	end
	unresponse[response] = co_address --表示当前服务 还欠 co_address 一个响应 ,此时co_address就是我们的main服务

	return response
end

此时我们应该回到main服务调用 skynet.newservice("db")的地方了

function skynet.newservice(name, ...)
	return skynet.call(".launcher", "lua" , "LAUNCH", "snlua", name, ...)
end

此时调用skynet.call挂起的协程,重新被唤醒,并返回地址给main服务了。

标签:服务,--,db,newservice,snlua,launcher,skynet,end
From: https://www.cnblogs.com/waittingforyou/p/16966134.html

相关文章

  • 2-skynet基本概况
    视频中的讲解和本系列博客是对应的,但不是完全相同的.这一节主要是建立大致印象。暂时不要太纠结于细节问题:一个skynet进程里面总共有什么线程工作线程怎么工......
  • 受skynet启发的分布式服务端框架设计
    简介不管是RPC还是IPC,本质都是通过某种寻址方式调用另一个工作单元(线程)的函数(subroutine)。此处工作单元可以是主机(host),进程(process),线程(thread)。最终函数将在某......