skynet.dispatch 函数详解
skynet.dispatch
是 skynet 框架中用于注册消息处理函数的核心 api。它的作用是为特定类型的消息绑定处理逻辑,当服务收到该类型的消息时,自动调用对应的处理函数。以下是其详细解析:
1. 函数定义与参数
skynet.dispatch(type, func)
type
:消息类型(字符串或数字)。- 常见类型:
"lua"
:默认的 lua 消息协议(对应skynet.ptype_lua
)。"socket"
:网络消息(对应skynet.ptype_socket
)。- 自定义类型:通过
skynet.register_protocol
注册的协议类型。
- 常见类型:
func
:消息处理函数,格式为function(session, source, ...)
。session
:会话 id,用于响应消息(如skynet.ret
)。source
:发送方服务的地址(skynet.address
格式)。...
:消息内容(由协议定义的解包逻辑生成)。
2. 消息处理流程
当服务收到一条消息时,skynet 会执行以下步骤:
- 协议匹配:根据消息类型(如
"lua"
)找到对应的解包函数。 - 消息解包:调用协议注册的
unpack
函数,将二进制数据解析为 lua 值。 - 分发处理:调用
skynet.dispatch
注册的处理函数,传入session
、source
和解包后的数据。 - 协程调度:处理函数在一个独立的协程中执行,避免阻塞其他消息处理。
3. 使用示例
示例 1:处理 lua 协议消息
local skynet = require "skynet" -- 注册 lua 类型消息的处理函数 skynet.dispatch("lua", function(session, source, cmd, ...) if cmd == "add" then local a, b = ... skynet.ret(skynet.pack(a + b)) elseif cmd == "ping" then skynet.ret(skynet.pack("pong")) end end) skynet.start(function() -- 服务初始化代码 end)
说明:
- 当收到
"lua"
类型的消息时,解析出命令cmd
和参数。 - 根据
cmd
执行逻辑,并通过skynet.ret
返回结果。
示例 2:处理自定义协议消息
local skynet = require "skynet" -- 注册自定义协议 skynet.register_protocol { name = "myproto", id = 100, -- 自定义协议 id(需唯一) unpack = function(msg, sz) -- 自定义解包逻辑(如 sproto 解析) return myproto.decode(msg, sz) end } -- 处理自定义协议消息 skynet.dispatch("myproto", function(session, source, data) print("received:", data) skynet.ret() -- 无返回值 end) skynet.start(function() -- 服务初始化代码 end)
- 自定义协议需要先通过
skynet.register_protocol
注册。 - 收到类型为
"myproto"
的消息时,调用自定义解包函数,并处理数据。
4. 关键机制
(1) 协程与阻塞操作
- 协程调度:每条消息的处理在独立协程中执行,互不阻塞。
- 阻塞 api:若处理函数中调用
skynet.call
、skynet.sleep
等阻塞 api,当前协程会被挂起,直到操作完成。
skynet.dispatch("lua", function(session, source, cmd) if cmd == "slow_task" then skynet.sleep(100) -- 挂起协程 1 秒 skynet.ret("done") end end)
(2) 消息响应
skynet.ret
:用于向发送方返回响应。- 若消息是请求(
skynet.call
),必须调用skynet.ret
。 - 若消息是通知(
skynet.send
),无需返回。
- 若消息是请求(
skynet.dispatch("lua", function(session, source, cmd) if session ~= 0 then -- 需要响应 skynet.ret(skynet.pack("response")) end end)
5. 与 skynet.register_protocol 的协作
协议注册:定义如何解析和打包消息。
skynet.register_protocol { name = "binary", id = skynet.ptype_user, -- 自定义 id unpack = function(msg, sz) return msg, sz end, -- 不解包,直接传递原始数据 pack = skynet.pack -- 默认打包函数 }
消息分发:通过 skynet.dispatch
绑定处理逻辑。
skynet.dispatch("binary", function(session, source, msg, sz) -- 处理二进制数据 end)
6. 注意事项
避免阻塞主线程:
若处理函数中有耗时操作(如大量计算、同步 io),应使用 skynet.fork
创建新协程。
skynet.dispatch("lua", function(session, source, cmd) if cmd == "heavy_task" then skynet.fork(function() -- 在子协程中执行耗时操作 local result = heavy_compute() skynet.ret(skynet.pack(result)) end) end end)
协程生命周期:
确保每个协程最终退出,避免内存泄漏(如通过 pcall
捕获异常)。
线程安全:
skynet 服务是单线程的,但协程间共享 lua 虚拟机状态,需谨慎处理共享数据(推荐使用 skynet.sharedata
)。
7. 典型应用场景
- rpc 调用:处理远程服务请求并返回结果。
- 网络消息:解析 tcp/udp 数据包,如游戏协议、http 请求。
- 定时任务:通过
skynet.timeout
触发延时逻辑。
总结
skynet.dispatch
是 skynet 服务的消息处理入口,通过绑定协议类型与处理函数,实现灵活的消息分发机制。理解其协程调度、协议注册和响应机制,是构建高效 skynet 服务的关键。结合 sproto
等协议工具,可以进一步简化网络通信的复杂性。
到此这篇关于skynet.dispatch 使用示例详解的文章就介绍到这了,更多相关skynet.dispatch 使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论