Skynet 常用 Lua API(面向游戏服务开发)
本文聚焦最常用的一批 Skynet Lua API:服务生命周期、消息收发(call/send)、定时与协程、环境与日志。每个 API 都包含:作用、参数、返回值、简单示例。
约定:示例默认在 Skynet 服务内运行(local skynet = require "skynet"),并使用"lua"协议。
1) skynet.start(start_func)
作用
- 作为服务入口,注册回调并启动服务初始化逻辑。Skynet 会在一个协程里执行
start_func,服务开始接收消息。
参数
start_func:function:初始化函数,通常在这里skynet.dispatch(...)、拉起子服务等。
返回值
- 无。
简单示例
local skynet = require "skynet"
skynet.start(function()
skynet.error("service start")
end)2) skynet.dispatch(typename, func)
作用
- 为指定协议注册消息分发函数。收到该协议消息时,Skynet 会创建协程调用
func(session, source, ...)。
参数
typename:string:协议名,常用"lua"。func:function|nil:- 传入函数:设置分发函数。
- 传入
nil:返回当前分发函数(如果存在)。
返回值
old_func:function|nil:当设置新函数时,返回旧的分发函数;当func == nil时返回当前分发函数。
简单示例
local skynet = require "skynet"
local function dispatch(session, source, cmd, ...)
if cmd == "ping" then
return skynet.retpack("pong")
end
error("unknown cmd")
end
skynet.start(function()
skynet.dispatch("lua", dispatch)
end)3) skynet.newservice(name, ...)
作用
- 创建一个新的服务实例并返回它的地址(handle)。同名服务可以创建多个实例。
参数
name:string:服务脚本名(luaservice路径里可找到的.lua服务文件名,不带扩展名)。...:传给新服务的启动参数(由新服务脚本自行解析)。
返回值
addr:number|string:新服务地址,可用于skynet.call/send。
简单示例
local skynet = require "skynet"
skynet.start(function()
local hello = skynet.newservice("game_hello")
local v = skynet.call(hello, "lua", "get")
skynet.error("counter =", v)
end)4) skynet.uniqueservice(name, ...)
作用
- 获取“全局唯一”的服务实例:如果已存在则复用,不存在则创建。
参数
name:string...:仅在首次创建时作为启动参数生效。
返回值
addr:number|string:唯一服务地址。
简单示例
local skynet = require "skynet"
skynet.start(function()
local dc = skynet.uniqueservice("datacenterd")
skynet.send(dc, "lua", "ping")
end)5) skynet.call(addr, typename, ...)
作用
- 同步 RPC:发送请求并等待对方返回。底层依赖
session机制,当前协程会挂起直到收到 response。
参数
addr:number|string:目标服务地址或名字。typename:string:协议名,常用"lua"。...:业务参数,会被该协议的pack打包发送。
返回值
...:对方用skynet.ret/skynet.retpack返回的内容(经unpack反序列化后展开)。
简单示例
local skynet = require "skynet"
skynet.start(function()
local hello = skynet.newservice("game_hello")
local new_value = skynet.call(hello, "lua", "incr", 5)
skynet.error("after incr:", new_value)
end)6) skynet.send(addr, typename, ...)
作用
- 异步发送:只负责投递消息,不等待返回。适合通知、日志、广播、异步任务触发等。
参数
addr:number|stringtypename:string...:业务参数。
返回值
ok:boolean|nil:底层发送结果(通常你不依赖它做业务判断)。
简单示例
local skynet = require "skynet"
skynet.start(function()
local hello = skynet.newservice("game_hello")
skynet.send(hello, "lua", "incr", 1)
skynet.error("sent incr without waiting")
end)7) skynet.ret(msg, sz) / skynet.retpack(...)
作用
- 在收到
skynet.call的请求时,用于把结果返回给调用方。 skynet.retpack(...)是最常用的封装:把参数序列化后返回。
参数
skynet.ret(msg, sz):msg:lightuserdata|string|nil:底层打包后的消息缓冲区(通常不手写)。sz:number|nil:长度。
skynet.retpack(...):...:要返回给调用方的 Lua 值。
返回值
skynet.ret:true|false(send触发的消息不需要返回,通常为false)。skynet.retpack:同skynet.ret。
简单示例
local skynet = require "skynet"
local function dispatch(session, source, cmd, a, b)
if cmd == "add" then
return skynet.retpack(a + b)
end
end
skynet.start(function()
skynet.dispatch("lua", dispatch)
end)8) skynet.fork(func, ...)
作用
- 在当前服务内创建一个新的协程执行
func,不会阻塞当前消息处理流程。常用于并行任务、后台循环等。
参数
func:function...:传给func的参数。
返回值
co:thread:Lua 协程对象(一般不需要手动操作)。
简单示例
local skynet = require "skynet"
skynet.start(function()
skynet.fork(function()
skynet.error("in fork")
end)
end)9) skynet.sleep(ti)
作用
- 让当前协程睡眠一段时间(不阻塞整个服务,只阻塞当前协程)。
参数
ti:number:睡眠时长,单位是“tick”(Skynet 内部时间片单位)。
返回值
- 无。
简单示例
local skynet = require "skynet"
skynet.start(function()
skynet.fork(function()
skynet.error("sleeping...")
skynet.sleep(100)
skynet.error("wake up")
end)
end)10) skynet.timeout(ti, func)
作用
- 定时执行:在
ti个 tick 之后执行一次func。
参数
ti:number:延迟 tick 数。func:function:到期执行的函数。
返回值
token:any:可用于skynet.wakeup(token)的令牌(常用来提前唤醒)。
简单示例
local skynet = require "skynet"
skynet.start(function()
skynet.timeout(50, function()
skynet.error("timeout fired")
end)
end)11) skynet.now()
作用
- 获取当前时间(tick 计数)。适合做简单的耗时统计与超时控制。
参数
- 无。
返回值
now:number:当前 tick。
简单示例
local skynet = require "skynet"
skynet.start(function()
local t1 = skynet.now()
skynet.sleep(10)
local t2 = skynet.now()
skynet.error("cost ticks:", t2 - t1)
end)12) skynet.self()
作用
- 获取当前服务自身的地址(handle)。
参数
- 无。
返回值
addr:number:当前服务地址。
简单示例
local skynet = require "skynet"
skynet.start(function()
skynet.error("self =", skynet.self())
end)13) skynet.exit()
作用
- 退出当前服务。常用于“一次性工作服务”完成任务后主动结束。
参数
- 无。
返回值
- 无。
简单示例
local skynet = require "skynet"
skynet.start(function()
skynet.error("do something then exit")
skynet.exit()
end)14) skynet.error(...)
作用
- 输出日志到 Skynet 的 logger。调试期最常用。
参数
...:任意 Lua 值,会被拼接输出。
返回值
- 无。
简单示例
local skynet = require "skynet"
skynet.start(function()
skynet.error("hello", 123, { a = 1 })
end)15) skynet.getenv(key) / skynet.setenv(key, value)
作用
- 读写环境变量(Skynet 运行时的全局键值),常用于配置开关、路径、节点信息等。
setenv只能设置不存在的 key(用于防止误覆盖)。
参数
skynet.getenv(key):key:string
skynet.setenv(key, value):key:stringvalue:string
返回值
skynet.getenv:value:string|nilskynet.setenv:无(失败会抛错)。
简单示例
local skynet = require "skynet"
skynet.start(function()
local daemon = skynet.getenv("daemon")
skynet.error("daemon =", daemon)
end)16) skynet.address(addr)
作用
- 把服务地址格式化成可读字符串,便于日志输出。
参数
addr:number|string
返回值
s:string
简单示例
local skynet = require "skynet"
skynet.start(function()
local self = skynet.self()
skynet.error("self =", skynet.address(self))
end)17) skynet.register_protocol(proto)
作用
- 注册自定义协议(name/id/pack/unpack/dispatch)。高级用法:自定义二进制协议、性能优化、接入网关协议等。
参数
proto:table:常用字段如下:name:string:协议名,例如"lua"。id:number:协议号。pack:function:把 Lua 参数打包成消息。unpack:function:把消息解包成 Lua 参数。dispatch:function|nil:可选,默认分发函数。
返回值
- 无(失败会抛错)。
简单示例
local skynet = require "skynet"
skynet.register_protocol {
name = "myproto",
id = 99,
pack = skynet.pack,
unpack = skynet.unpack,
}18) 常见组合用法(建议你记住)
18.1 命令式服务接口(cmd 分发)
作用
- 统一把服务对外能力表达为
cmd,调用方只需要call/send(addr, "lua", cmd, ...)。
简单示例
local skynet = require "skynet"
local handlers = {}
function handlers.get()
return 0
end
local function dispatch(session, source, cmd, ...)
local f = handlers[cmd]
if not f then
error("unknown cmd: " .. tostring(cmd))
end
return skynet.retpack(f(...))
end
skynet.start(function()
skynet.dispatch("lua", dispatch)
end)18.2 call 用于要结果,send 用于通知
作用
call:强依赖返回值的流程(登录校验、分配ID、读写关键数据)。send:不需要立刻返回的流程(通知、日志、异步触发、广播)。
19) 你下一步最该练的三个点
- 把每个服务的对外接口收敛成
cmd表(handlers 模式)。 - 统一定义请求/返回的数据结构(哪怕先用普通 table,也要保持字段一致)。
- 对
call增加超时策略:避免因为对方卡死导致协程长期挂起(可以从设计层规避,或用 watchdog/监控服务发现异常)。
评论(0)