Skynet框架内部实现了一套消息处理过程,消息数据包在业务上是请求或回应,消息采用队列的方式进行处理,而处理者就是服务。
服务API
local skynet = require("skynet")
- 获取注册表中的变量值
skynet.getenv(varname)
- 设置注册表
skynet.setenv(name, value)
- 错误打印输出
skynet.error(...)
- 开启服务,使用回调函数初始化服务并将消息处理函数注册到C层。
skynet.start(func)
- 结束当前服务
skynet.exit()
- 获取当前服务句柄
skynet.self()
- 将服务句柄转换为字符串
skynet.address(handle)
- 退出Skynet进程
require "skynet.manager"
skynet.abort()
- 强制关闭服务
skynet.kill(address)
入门服务
载入Skynet并开启服务
# 确保当前目录位于skynet根目录下
$ pwd
# 创建目录并配置参数
$ mkdir demo
$ sudo cp ./example/config ./demo
$ sudo cp ./example/config.path ./demo
$ vim config.path
# 将config.path中的example目录替换或加入为demo目录
# 创建文件并编写服务
$ cd demo
$ vim simple.lua
local skynet = require "skynet"
skynet.start(function()
skynet.error("Server start")
end)
# 开启服务
$ ./skynet demo/config
环境变量
- 预先记载的环境变量是在
config
中配置的,加载完毕后所有的服务service
都能去获取已设置的环境变量。 - 可以设置环境变量但不能修改已经存在的环境变量
- 环境变量设置完成后当前节点上的所有服务都能访问到
- 环境变量设置完成后当服务退出时,环境变量依然会存在。
$ vim ./demo/simple.lua
local skynet = require "skynet"
skynet.start(function()
-- 获取默认配置
skynet.error(skynet.getenv(skynet.address))
-- 自定义配置并获取
skynet.setenv("author", "junchow")
skynet.error(skynet.getenv("author"))
-- 退出服务节点
skynet.exit()
end)
$ ./skynet ./demo/simple.lua
服务初始化
skynet.init
用于注册服务之前的初始化,也就是在skynet.start
之前运行。
$ vim ./demo/simple.lua
local skynet = require "skynet"
skynet.init(function()
skynet.error("skynet server initialize")
end)
skynet.start(function()
skynet.error("skynet server start")
end)
$ ./skynet ./demo/simple.lua
[:01000009] Server initialize
[:01000009] Server start
服务类型
Skynet中的服务分为普通服务和全局唯一服务:
全局唯一服务
全局唯一的服务等同于单例,也就是说只能生成一个服务实例,不管调用多少次创建接口,最后都只会创建一个此类型的服务实例且全局唯一。
创建全局唯一服务
-- 创建当前节点的全局唯一服务
skynet.uniqueservice(name, ...)
-- 创建所有节点的全局唯一服务
-- 参数true表示此服务在所有节点之间是唯一的
skynet.uniqueservice(true, name, ...)
当调用uniqueservice
只传入一个服务名时,表示创建当前Skynet节点的全局唯一服务。当第一个参数传递true
,第二个参数传递服务名称时,则表示创建所有节点的全局唯一服务。创建成功后,若是第一次创建则返回服务地址,若是第二次创建则返回第一次创建的服务地址。
# 进入skynet目录
$ cd skynet
# 创建demo目录
$ mkdir demo
# 拷贝example目录下的config配置到demo目录
$ cp ./example/config ./demo
# 拷贝example目录下的路径配置 config.path 到 demo 目录
$ cp ./example/config.path ./
# 进入demo目录
$ cd demo
# 修改路径配置,添加demo目录到luaservice目录下和snax目录下
$ vim config.path
root = "./"
luaservice = root.."service/?.lua;"..root.."demo/?.lua;"
lualoader = root."lualib/loader.lua"
lua_path = root.."lualib/?.lua;"..root.."lualib/?/init.lua"
lua_cpath = root.."luaclib/?.so"
snax = root.."demo/?.lua"
# 创建服务
$ vim serviceunique.lua
local skynet = require "skynet"
skynet.start(function()
skynet.error("uniqueservice is running");
end)
# 创建测试文件
$ vim serviceunique_test.lua
-- 引入skynet框架
local skynet = require "skynet"
-- 设置默认参数
local args = {...}
if #args==0 then
table.insert(args, "uniqueservice")
end
-- 启动服务
skynet.start(function()
skynet.error("uniqueservice is start")
local us
if #args==2 and args[1]=="true" then
us = skynet.uniqueservice("true", args[2])
else
us = skynet.uniqueservice(args[1])
end
skynet.error("uniqueservice hanlder is ", skynet.address(us))
end)
# 修改配置中启动脚本为uniqueservice_test
$ vim config
include "config.path"
thread = 8
logger = nil
logpath = "."
harbor = 1
address = "127.0.0.1:2526"
master = "127.0.0.1:2013"
start = "uniqueservice_test"
bootstrap = "snlua bootstrap"
standalone = "0.0.0.0:2013"
cpath = root.."cservice/?.so"
# 运行服务
$ ./skynet ./demo/config
[:01000009] LAUNCH snlua uniqueservice_test
[:01000009] unqiueservice is start
[:0100000a] LAUNCH snlua uniqueservice
[:0100000a] uniqueservice is running
[:01000009] uniqueservice handler is 0100000a
查询全局唯一服务
若不清楚当前是否创建了全局唯一服务,可通过queryservice
接口来查询,若没有创建则会一直等待直到目标服务被创建。当参数带true
时则表示在所有节点中查询是否存在唯一的服务。
-- 若没有创建则会一直等待直到目标服务被创建
skynet.queryservice(name,...)
-- `true`表示在所有节点中查询是否存在唯一的服务
skynet.queryservice(true, name, ...)
调用queryservice
时可以选择是否传递第一个参数true
,表示查询的当前Skynet节点的全局唯一服,还是所有节点的全局唯一服。
这两种全局唯一服作用范围不同,所以可以同时存在同名但作用范围不同的全局唯一服。
普通服务
在每次调用创建接口时都会产生一个与之对应的服务实例。可以同时创建多个服务实例,并使用唯一的ID来区分每个服务实例。