下面给你整理一份 《Skynet dispatch 使用示例详解(超全)》,从概念、原理到实战示例,让你彻底弄懂服务端消息处理的核心机制。


一、skynet.dispatch 是什么?

在 Skynet 框架中,所有 服务之间的消息通信,都依赖于 dispatch 来处理:

  • 作用:注册消息处理函数,决定服务收到消息后如何处理
  • 典型用法
skynet.dispatch("lua", function(session, source, cmd, ...)
    -- 处理消息逻辑
end)

  • 第一个参数:消息类型(常用 "lua""text" 等)
  • 第二个参数:回调函数,参数通常是:
    • session:会话 ID,用于返回结果
    • source:发送消息的服务地址
    • ...:消息内容(由发送方传递)

二、dispatch 参数详解

skynet.dispatch(proto, func)

参数说明
proto消息类型,例如 "lua""text"、自定义协议
func回调函数,形式:function(session, source, ...)
  • session = 0:表示消息是单向的(send 发送)
  • session > 0:表示消息可回复(call / rawcall)

三、dispatch 使用场景

  1. 处理普通 RPC 请求
  2. 处理异步消息 / 通知
  3. 自定义协议消息
  4. 内部服务通信

四、dispatch 基本示例

服务端 user.lua

local skynet = require "skynet"

local CMD = {}

function CMD.getName(uid)
    return "User_" .. uid
end

function CMD.add(a, b)
    return a + b
end

-- 注册消息处理
skynet.start(function()
    skynet.dispatch("lua", function(session, source, cmd, ...)
        local f = CMD[cmd]
        if f then
            skynet.ret(skynet.pack(f(...))) -- 返回结果给调用方
        else
            skynet.error("Unknown command:", cmd)
        end
    end)
end)

客户端调用

local skynet = require "skynet"

local name = skynet.call(".user", "lua", "getName", 1001)
print(name)  -- 输出:User_1001

local sum = skynet.call(".user", "lua", "add", 10, 20)
print(sum)   -- 输出:30

  • 核心:dispatch 注册了 "lua" 类型的消息处理
  • call 自动挂起协程,dispatch 返回结果后协程恢复

五、dispatch 异步消息示例

  • 使用 skynet.send 发送通知
  • session = 0,不需要返回值

客户端发送

skynet.send(".user", "lua", "notify", "Hello World")

服务端 dispatch

skynet.dispatch("lua", function(session, source, cmd, msg)
    if cmd == "notify" then
        skynet.info("Received message:", msg)
    end
    -- session = 0,不返回
end)

特点:

  • 异步消息不会阻塞调用方
  • dispatch 可以同时处理多种消息类型

六、dispatch 多协议示例

-- 处理 lua 消息
skynet.dispatch("lua", function(session, source, cmd, ...)
    print("Lua message:", cmd, ...)
end)

-- 处理 text 消息
skynet.dispatch("text", function(session, source, msg)
    print("Text message:", msg)
end)

  • 适用于服务同时处理 RPC、日志通知、文本命令等

七、dispatch + rawcall 示例

skynet.dispatch("lua", function(session, source, cmd, ...)
    if cmd == "getName" then
        local reply = "User_" .. ...
        skynet.ret(skynet.pack(reply))  -- 可用于 rawcall 或 call
    end
end)

  • rawcall 发送消息时也会被 dispatch 拦截
  • 手动处理返回值

八、dispatch 高级用法

1. 使用 CMD 表集中管理命令

local CMD = {}

function CMD.hello()
    return "Hello Skynet"
end

function CMD.add(a, b)
    return a + b
end

skynet.dispatch("lua", function(session, source, cmd, ...)
    local f = CMD[cmd]
    if f then
        skynet.ret(skynet.pack(f(...)))
    else
        skynet.error("Unknown cmd:", cmd)
    end
end)

2. 防止并发冲突

  • 对于需要顺序执行的操作,可以使用 skynet.queue
local skynet = require "skynet"
local queue = require "skynet.queue"
local q = queue()

skynet.dispatch("lua", function(session, source, cmd, ...)
    q(function()
        -- 顺序处理 cmd
        skynet.ret(skynet.pack(CMD[cmd](...)))
    end)
end)


九、dispatch 注意事项

  1. session 管理
    • call / rawcall 消息的 session > 0
    • send 消息 session = 0,不返回
  2. 返回值处理
    • 必须使用 skynet.ret(skynet.pack(...)) 返回结果
  3. 并发处理
    • 默认 dispatch 是并发处理的
    • 对共享资源操作建议用 skynet.queue 或自定义锁
  4. 多协议共存
    • 可以同时注册 "lua""text" 等多种协议
  5. 错误捕获
    • dispatch 内部异常不会影响 Skynet 框架,但会打印日志

十、dispatch 核心总结

  • 作用:注册消息处理函数,是 Skynet 服务端处理消息的核心
  • 用法skynet.dispatch(proto, func)
  • 关键点
    1. proto 对应消息类型
    2. func 参数 (session, source, ...)
    3. call 消息需要 skynet.ret 返回
    4. send 消息 session = 0,无返回
  • 典型场景
    • RPC 请求处理(call / rawcall)
    • 异步通知处理(send)
    • 日志、心跳、状态同步等内部通信