目录
- skynet.call 详细解析
- 1. 函数签名与参数
- 2. 内部实现机制
- 3. 会话ID与协程调度
- 4. 超时与错误处理
- 5. 返回值处理
- 6. 协议类型的影响
- 7. skynet.call vs skynet.send
- 8. 示例代码分析
- 9. 最佳实践
- 10. 总结
skynet.call 详细解析
1. 函数签名与参数
函数签名:
skynet.call(addr, typename, ...)
addr
:目标服务的地址(整数或字符串形式的服务名)。typename
:消息协议类型(如"lua"
、"text"
),决定消息的编码方式。...
:消息内容(具体参数,可以是任意Lua值)。
示例:
local result = skynet.call("db_service", "lua", "query", "SELECT * FROM users")
2. 内部实现机制
- 同步调用:
skynet.call
是同步操作,发送请求后阻塞当前协程,直到收到响应。 - 会话管理:
- 生成会话ID:调用时生成唯一的会话ID(
session
),用于匹配请求与响应。 - 发送消息:将消息和会话ID发送到目标服务。
- 协程挂起:当前协程通过
skynet.wait
挂起,等待响应。 - 响应处理:目标服务处理完成后,通过会话ID返回结果,唤醒挂起的协程。
- 生成会话ID:调用时生成唯一的会话ID(
3. 会话ID与协程调度
- 会话ID:每个
skynet.call
调用对应一个唯一会话ID,确保请求与响应一一匹配。 - 协程关联:会话ID与当前协程绑定,响应到达时通过会话ID找到对应协程并唤醒。
4. 超时与错误处理
- 默认无超时:
skynet.call
默认无限等待响应,若目标服务未响应,协程将永久挂起。 - 手动超时:可通过
skynet.timeout
结合skynet.response
实现超时逻辑:local response = skynet.response() skynet.timeout(500, function()response(false, "Timeout") end) local result = skynet.call("service", "lua", "slow_task")
- 错误传递:若目标服务抛出错误,
skynet.call
会将错误信息通过skynet.ret
返回。
5. 返回值处理
- 多返回值支持:目标服务可通过
skynet.ret(skynet.pack(a, b))
返回多个值。 - 返回值解包:
skynet.call
自动解包返回值,直接返回多个结果:local a, b = skynet.call("service", "lua", "get_values")
6. 协议类型的影响
"lua"
协议:- 编码方式:使用
skynet.pack
和skynet.unpack
序列化数据。 - 适用场景:服务间结构化数据传递(推荐)。
- 编码方式:使用
"text"
协议:- 编码方式:直接传递字符串,无需序列化。
- 适用场景:简单文本消息或调试。
- 自定义协议:需通过
skynet.register_protocol
注册编码/解码函数。
7. skynet.call vs skynet.send
特性 | skynet.call | skynet.send |
---|---|---|
同步/异步 | 同步(阻塞等待响应) | 异步(立即返回) |
返回值 | 返回目标服务的响应 | 无返回值 |
会话ID | 自动生成并管理 | 无需会话ID |
典型场景 | 需要即时结果的请求(如数据库查询) | 通知型消息(如日志记录、事件触发) |
8. 示例代码分析
服务端处理请求:
-- 目标服务(db_service)
skynet.start(function()skynet.dispatch("lua", function(session, source, cmd, ...)if cmd == "query" thenlocal sql = ...local data = execute_query(sql)skynet.ret(skynet.pack(data)) -- 返回查询结果endend)
end)
客户端调用:
-- 调用方服务
local result = skynet.call("db_service", "lua", "query", "SELECT * FROM users")
print("Query result:", result)
9. 最佳实践
- 协议选择:优先使用
"lua"
协议,支持复杂数据结构。 - 超时机制:关键操作添加超时逻辑,避免服务死锁。
- 错误处理:在目标服务中捕获异常并通过
skynet.ret
返回错误信息。 - 避免阻塞:长时间操作使用
skynet.fork
创建子协程,避免阻塞主消息循环。
10. 总结
skynet.call
是 Skynet 中实现服务间同步调用的核心 API,通过会话ID和协程调度机制实现高效的请求-响应模型。理解其内部机制和协议类型的选择,能够帮助开发者构建稳定、高效的服务间通信逻辑。