4 服务类型
skynet中的服务分为普通服务与全局唯一服务。第3节启动方式就是一个普通服务,而全局唯一服务顾名思义就是在skynet中只能生成一个服务实例。
4.1 普通服务
每调用一次创建接口就会创建出一个对应的服务实例,可以同时创建成千上万个,用唯一的id来区分每个服务实例。使用的创建接口是:
--[[
1. 用于启动一个新的 Lua 服务,luaServerName是脚本的名字(不用写 .lua 后缀)。
2. 只有被启动的脚本的 start 函数返回后,这个 API 才会返回启动的服务的地址,这是一个阻塞 API 。
3. 如果被启动的脚本在初始化环节抛出异常,skynet.newservice 也会执行失败。
4. 如果被启动的脚本的 start 函数是一个永不结束的循环,那么 newservice 也会被永远阻塞住。
--]]
skynet.newservice(luaServerName, ...)
启动一个test服务
testnewservice.lua
local skynet = require "skynet"
--调用skynet.start接口,并定义传入回调函数
skynet.start(function()
skynet.error("My new service")
skynet.newservice("test")
skynet.error("new test service")
end)
启动main.lua,并且输入testnewservice
$ ./skynet examples/config #默认启动main.lua服务
testnewservice
[:01000010] LAUNCH snlua testnewservice #通过main服务,启动testnewservice服务
[:01000010] My new service
[:01000012] LAUNCH snlua test #再启动test服务
[:01000012] Server First Test
[:01000010] new test service
启动两个test服务
testnewservice2.lua
local skynet = require "skynet"
--调用skynet.start接口,并定义传入回调函数
skynet.start(function()
skynet.error("My new service")
skynet.newservice("test")
skynet.error("new test service 0")
skynet.newservice("test")
skynet.error("new test service 1")
end)
启动main.lua,并且输入testnewservice
$ ./skynet examples/config #默认启动main.lua服务
testnewservice #终端输入
[:01000010] LAUNCH snlua testnewservice #通过main服务,启动testnewservice服务
[:01000010] My new service
[:01000012] LAUNCH snlua test #启动一个test服务
[:01000012] Server First Test
[:01000010] new test service 0
[:01000019] LAUNCH snlua test #再启动一个test服务
[:01000019] Server First Test
[:01000010] new test service 1
4.2 全局唯一服务
全局唯一的服务等同于单例,即不管调用多少次创建接口,最后都只会创建一个此类型的服务实例,且全局唯一。
创建接口:
skynet.uniqueservice(servicename, ...)
skynet.uniqueservice(true, servicename, ...)
当带参数 true 时,则表示此服务在所有节点之间是唯一的。第一次创建唯一服,返回服务地址,第二次创建的时候不会正常创建服务,只是返回第一次创建的服务地址。
查询接口: 假如不清楚当前创建了此全局服务没有,可以通过以下接口来查询:
skynet.queryservice(servicename, ...)
skynet.queryservice(true, servicename, ...)
如果还没有创建过目标服务则一直等下去,直到目标服务被(其他服务触发而)创建。
当参数 带true 时,则表示查询在所有节点中唯一的服务是否存在。
4.2.1 测试skynet.uniqueservice接口
示例:testunique.lua
local skynet = require "skynet"
local args = {
... }
if(#args == 0) then
table.insert(args, "uniqueservice")
end
skynet.start(function()
local us
skynet.error("test unique service")
if ( #args == 2 and args[1] == "true" ) then
us = skynet.uniqueservice(true, args[2])
else
us =skynet.uniqueservice(args[1])
end
skynet.error("uniqueservice handler:", skynet.address(us))
end)
示例:uniqueservice.lua
local skynet = require "skynet"
skynet.start(function()
skynet.error("Server First Test")
--skynet.exit() 不要尝试服务初始化阶段退出服务,唯一服会创建失败
end)
运行结果:
$ ./skynet examples/config
testunique #终端输入
[:01000010] LAUNCH snlua testunique
[:01000010] test unique service
[:01000012] LAUNCH snlua uniqueservice #第一次创建全局唯一服uniqueservice成功
[:01000012] unique service start
[:01000010] uniqueservice handler: :01000012
testunique #终端输入
[:01000019] LAUNCH snlua testunique
[:01000019] test unique service
[:01000019] uniqueservice handler: :01000012 #第二次创建并没有创建全局唯一服
4.2.2 测试skynet.queryservice接口
示例:testqueryservice.lua
local skynet = require "skynet"
local args = {
... }
if(#args == 0) then
table.insert(args, "uniqueservice")
end
skynet.start(function()
local us
skynet.error("start query service")
--如果test服务未被创建,该接口将会阻塞,后面的代码将不会执行
if ( #args == 2 and args[1] == "true" ) then
us = skynet.queryservice(true, args[2])
else
us = skynet.queryservice(args[1])
end
skynet.error("end query service handler:", skynet.address(us))
end)
运行结果:
如果不启动test全局唯一服务,直接执行查询函数
$ ./skynet examples/config
testqueryservice #终端输入
[:01000010] LAUNCH snlua testqueryservice
[:01000010] start query service #阻塞住,不再执行后面的代码
启动test全局唯一服务,再执行查询函数
$ ./skynet examples/config
testunique #终端输入
[:01000010] LAUNCH snlua testunique
[:01000010] test unique service
[:01000012] LAUNCH snlua uniqueservice #第一次创建全局唯一服成功
[:01000012] Server First Test
[:01000010] uniqueservice handler: :01000012
testqueryservice
[:01000019] LAUNCH snlua testqueryservice #再启动查询
[:01000019] start query service
[:01000019] end query service handler: :01000012 #skynet.queryservice将会返回
注意:
当调用uniqueservice只传一个服务名时,表示创建当前skynet节点的全局唯一服务。当第一个参数传递true,第二个参数传递服务名时,则表示所有节点的全局唯一服务。
调用queryservice时,也可以选择是否传递第一个参数true, 表示查询的是当前skynet节点的全局唯一服,还是所有节点的全局唯一服。这两种全局唯一服作用范围是不同,所有可以同时存在同名的但作用范围不同的全局唯一服。
4.3 多节点中的全局服务
4.3.1 启动两个skynet节点
首先,我们先启动两个节点出来。copy两个份examp/config为config1与config2, config1中修改如下:
config1:
include "config.path"
-- preload = "./examples/preload.lua" -- run preload.lua before every lua service run
thread = 2
logger = nil
logpath = "."
harbor = 1 --表示每个节点编号
address = "127.0.0.1:2526"
master = "127.0.0.1:2013"
start = "console" -- main script 只启动一个console.lua服务
bootstrap = "snlua bootstrap" -- The service for bootstrap
standalone = "0.0.0.0:2013" --主节点才会用到这个,绑定地址
-- snax_interface_g = "snax_g"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"
config2:
include "config.path"
-- preload = "./examples/preload.lua" -- run preload.lua before every lua service run
thread = 2
logger = nil
logpath = "."
harbor = 2 --编号需要改
address = "127.0.0.1:2527" --改一个跟config1不同的端口
master = "127.0.0.1:2013" --主节点地址不变
start = "console" -- main script
bootstrap = "snlua bootstrap" -- The service for bootstrap
--standalone = "0.0.0.0:2013" --作为从节点,就注释掉这里
-- snax_interface_g = "snax_g"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"
启动两个终端分别启动如下:
节点1启动:
./skynet examples/config1
[:01000001] LAUNCH logger
[:01000002] LAUNCH snlua bootstrap
[:01000003] LAUNCH snlua launcher
[:01000004] LAUNCH snlua cmaster #启动主节点cmaster服务
[:01000004] master listen socket 0.0.0.0:2013 #监听端口2013
[:01000005] LAUNCH snlua cslave #主节点也要启动一个cslave,去连接cmaster节点
[:01000005] slave connect to master 127.0.0.1:2013 #cslave中一旦连接完cmaster就会启动一个harbor服务
[:01000004] connect from 127.0.0.1:47660 4
[:01000006] LAUNCH harbor 1 16777221 #cslave启动一个Harbor服务 用于节点间通信
[:01000004] Harbor 1 (fd=4) report 127.0.0.1:2526 #报告cmaster cslave服务的地址
[:01000005] Waiting for 0 harbors #cmaster告诉cslave还有多少个其他cslave需要连接
[:01000005] Shakehand ready #cslave与cmaster握手成功
[:01000007] LAUNCH snlua datacenterd
[:01000008] LAUNCH snlua service_mgr
[:01000009] LAUNCH snlua console
[:01000002] KILL self
[:01000004] connect from 127.0.0.1:47670 6 #cmaster收到其他cslave连接请求
[:01000004] Harbor 2 (fd=6) report 127.0.0.1:2527 #其他cslave报告地址
[:01000005] Connect to harbor 2 (fd=7), 127.0.0.1:2527 #让当前cslave去连接其他cslave
节点2启动:
./skynet examples/config2
[:02000001] LAUNCH logger
[:02000002] LAUNCH snlua bootstrap
[:02000003] LAUNCH snlua launcher
[:02000004] LAUNCH snlua cslave
[:02000004] slave connect to master 127.0.0.1:2013 #cslave去连接主节点的cmaster服务
[:02000005] LAUNCH harbor 2 33554436 #cslave也启动一个harbor服务
[:02000004] Waiting for 1 harbors #等待主节点的cslave来连接
[:02000004] New connection (fd = 3, 127.0.0.1:37470) #cslave与主节点cslave连接成功
[:02000004] Harbor 1 connected (fd = 3)
[:02000004] Shakehand ready #cslave与cmaster握手成功
[:02000006] LAUNCH snlua service_mgr
[:02000007] LAUNCH snlua console
[:02000002] KILL self
4.3.2 测试全节点全局唯一服
在第一个节点中启动testunique.lua服务,然后第二个节点中启动testqueryservice.lua服务查询
节点1:
testunique true uniqueservice #所有节点全局唯一服方式启动
[:0100000b] LAUNCH snlua testunique true uniqueservice
[:0100000b] test unique service
[:0100000c] LAUNCH snlua uniqueservice
[:0100000c] Server First Test
[:0100000b] uniqueservice handler: :0100000c
节点2:
testqueryservice true uniqueservice
[:02000012] LAUNCH snlua testqueryservice true uniqueservice
[:02000012] start query service
[:02000012] end query service handler: :0100000b#节点1中已经启动了,所以节点2中
4.3.3 本地全局唯一服与全节点全局唯一服区别
节点2还可以创建一个同脚本的本地全局唯一服:
testunique uniqueservice
[:0100000c] LAUNCH snlua testunique
[:0100000c] test unique service
[:0100000d] LAUNCH snlua uniqueservice
[:0100000d] Server First Test
[:0100000c] uniqueservice handler: :0100000d #创建了一个本地全局唯一服
但是无法创建一个新的全节点全局唯一服:
testunique true uniqueservice
[:0100000e] LAUNCH snlua testunique true uniqueservice
[:0100000e] test unique service
[:0100000e] uniqueservice handler: :0100000b #还是节点1的全局唯一服句柄
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq769651718/article/details/79432858