在前面的文章:skynet:session 中,已經使用過 skynet.ret / skynet.retpack 對消息進行應答。但這兩個函數有一個使用限制,即:消息接收與消息應答必須在同一個協程裏完成,也就是說:請求被哪一個協程接收,就必須在這個協程響應。
這是因爲在 skynet 中,當一個服務收到一個消息的時候,會啓動一個協程來處理,並把協程句柄與發送消息的服務地址進行一一對應記錄在 table 中。當需要響應時,就使用當前調用 skynet.ret / skynet.retpack 的協程句柄去 table 中查詢對應的服務地址,然後把消息發給這個服務地址。
若在其他協程中調用 skynet.ret / skynet.retpack,那麼就會使用該協程句柄去查詢服務地址,最後肯定是查不到的。
解決方法:response 可實現接受請求與響應請求在不同協程中完成。
一、echoluamsg.lua
修改前一篇文章:skynet:session 中的 echoluamsg.lua,testforkcall.lua 與 main.lua 保持不變。
skynet = require "skynet"
require "skynet.manager"
skynet.start(function()
skynet.register("echoluamsg")
skynet.dispatch("lua", function(session, address, msg)
--先把發送服務地址以及session打包到閉包中,可以在任意地方調用
local response = skynet.response(skynet.pack)--指定打包函數
skynet.fork(function(msg)--開啓一個新的協程來處理響應
skynet.sleep(500)
skynet.error("recv " .. msg)
response(true, msg:upper())--第一個參數true表示應答成功,false則應答錯誤消息
end, msg)
end)
end)
-
local response = skynet.response(pack)
- pack:響應消息打包函數,默認爲 skynet.pack;
- 返回值:一個閉包函數。
-
response(ok, …)
參數 ok 的值可以是:- “test”:檢查接收響應的服務是否存在;
- true:發送應答 PTYPE_RESPONSE;
- false:發送 PTYPE_ERROR 錯誤消息。