胖仔

文章 分类 评论
10 6 0

站点介绍

胖仔的个人技术学习、心得、日常的分享站

skynet常见API丶lua

胖仔配猪 2026-03-17 57 0条评论 Skynet框架学习 skynet文档

首页 / 正文

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|string
  • typename: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.rettrue|falsesend 触发的消息不需要返回,通常为 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:string
    • value:string

返回值

  • skynet.getenvvalue:string|nil
  • skynet.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) 你下一步最该练的三个点

  1. 把每个服务的对外接口收敛成 cmd 表(handlers 模式)。
  2. 统一定义请求/返回的数据结构(哪怕先用普通 table,也要保持字段一致)。
  3. call 增加超时策略:避免因为对方卡死导致协程长期挂起(可以从设计层规避,或用 watchdog/监控服务发现异常)。

评论(0)


赣ICP备2025055021号-3

日历

2026年04月

   1234
567891011
12131415161718
19202122232425
2627282930  

文章目录