Skynet基礎入門例子詳解(2)

服務消息分發和迴應

同樣在同一個目錄建立3個文件(config,main.lua,service2.lua) 
config文件參考上一節

main.lua代碼:

local skynet = require "skynet"

-- 啓動服務(啓動函數)
skynet.start(function()
    -- 啓動函數裏調用Skynet API開發各種服務
    print("======Server start=======")
    -- skynet.newservice(name, ...)啓動一個新的 Lua 服務(服務腳本文件名)

    local service2 = skynet.newservice("service2")
    -- 向service2服務發出請求,設置key1的值
    skynet.call(service2,"lua","set","key1","value111111")  
    -- 向service2服務發出請求,獲取key1的值
    local kv = skynet.call(service2,"lua","get","key1")
    print(kv)

    -- 退出當前的服務
    skynet.exit()
end)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

skynet.send(address, typename, …) 把一條類別爲 typename 的消息發送給 address 。它會先經過事先註冊的 pack 函數打包 … 的內容。 
skynet.send 是一條非阻塞 API ,發送完消息後,coroutine 會繼續向下運行,這期間服務不會重入。

skynet.call(address, typename, …) 這條 API 則不同,它會在內部生成一個唯一 session ,並向 address 提起請求,並阻塞等待對 session 的迴應(可以不由 address 迴應)。當消息迴應後,還會通過之前註冊的 unpack 函數解包。

尤其需要留意的是,skynet.call 僅僅阻塞住當前的 coroutine ,而沒有阻塞整個服務。在等待迴應期間,服務照樣可以響應其他請求。所以,尤其要注意,在 skynet.call 之前獲得的服務內的狀態,到返回後,很有可能改變。

service2.lua代碼:

-- 每個服務獨立, 都需要引入skynet
local skynet = require "skynet"
require "skynet.manager"    -- 引入 skynet.register
local db = {}

local command = {}

function command.get(key)
    print("comman.get:"..key)   
    return db[key]
end

function command.set(key, value)
    print("comman.set:key="..key..",value:"..value) 
    db[key] = value
    local last = db[key]
    return last
end

skynet.start(function()
    print("==========Service2 Start=========")
    skynet.dispatch("lua", function(session, address, cmd, ...)
        print("==========Service2 dispatch============"..cmd)
        local f = command[cmd]      
        if f then
            -- 迴應一個消息可以使用 skynet.ret(message, size) 。
            -- 它會將 message size 對應的消息附上當前消息的 session ,以及 skynet.PTYPE_RESPONSE 這個類別,發送給當前消息的來源 source 
            skynet.ret(skynet.pack(f(...))) --迴應消息
        else
            error(string.format("Unknown command %s", tostring(cmd)))
        end
    end)
    --可以爲自己註冊一個別名。(別名必須在 32 個字符以內)
    skynet.register "SERVICE2"
end)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

迴應一個消息可以使用 skynet.ret(message, size) 。它會將 message size 對應的消息附上當前消息的 session ,以及 skynet.PTYPE_RESPONSE 這個類別,發送給當前消息的來源 source 。 
由於某些歷史原因(早期的 skynet 默認消息類別是文本,而沒有經過特殊編碼),這個 API 被設計成傳遞一個 C 指針和長度,而不是經過當前消息的 pack 函數打包。或者你也可以省略 size 而傳入一個字符串。

由於 skynet 中最常用的消息類別是 lua ,這種消息是經過 skynet.pack 打包的,所以慣用法是 skynet.ret(skynet.pack(…)) 。 
skynet.pack(…) 返回一個 lightuserdata 和一個長度,符合 skynet.ret 的參數需求;與之對應的是 skynet.unpack(message, size) 它可以把一個 C 指針加長度的消息解碼成一組 Lua 對象。

運行程序:

./skynet ./myexample/e1/config
  • 1
  • 2
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章