skynet 入門筆記(2):service 消息收發 原

Skynet 入門筆記(2):Service 消息收發

編寫第一個 service 成功了,接下來考慮多個 service 之間如何通信的問題。

skynet 是單進程多線程框架,每個 lua service 獨立運行在自己的 lua vm 裏,採用 actor 併發模型。

這篇博客要實現的是讓一個 service 發送消息,另一個 service 處理消息。

actor 併發模型

Actor模型又稱爲參與者模型,基本理念是每個併發的線程(或者進程、服務等其他併發的東西)都是一個參與者,參與者之間互相發送消息,決定如何迴應消息或者啓動更多參與者。

用人話來說,就是參與者給另一個參與者發送消息,然後繼續幹自己的事情;收到消息的參與者決定要怎麼處理消息:做點什麼,創建新參與者,或者拋棄這個消息。

skynet 啓動新 service

依照前文配置 skynet

修改project/service/main.lua

-- main.lua
local skynet = require "skynet"

skynet.start(function()
    -- print("Hello world")
    skynet.newservice "myservice/worker"
    skynet.newservice "myservice/msg_dispatcher"
    skynet.exit()
end)

主要修改的地方是加入了兩行skynet.newservice

api參考文檔在這裏

確實挺簡陋的,就一句話。

newservice(name, ...) 啓動一個名爲 name 的新服務。

name參數注意用相對於project/service的路徑即可,不用加lua的後綴名。

消息發送者

project/service裏創建目錄myservice,然後在裏面創建新文件msg_dispatcher.lua

-- msg_dispatcher.lua
local skynet = require "skynet"

function sendmsg()
    skynet.send("worker", "lua", "say", "Hello world!")
    skynet.timeout(100, sendmsg)
end

skynet.start(function()
    skynet.timeout(100, sendmsg)
end)

其中 function skynet.timeout(ti, func) 是定時器,第一個參數是時間,單位是 1/100 秒,第二個參數是回調函數。

然後是function skynet.send(addr, type, ...),第一個addr是服務的地址,這個地址可以是服務的32位整數識別id,也可以是字符串別名;別名需要該服務自行註冊才能使用。第二個type參數是消息類型,常用的就是lua雖然我也不知道爲啥常用但大家都這麼用。後面的變長參數一般來說第一個約定是命令類型,再往後是命令參數,看下面的處理就知道了。

消息處理者

project/service/myservice裏創建文件worker.lua,然後這麼寫。

-- work.lua
local CMD = {}

CMD.say = function (text)
    print(text)
end

skynet.start(function()
    skynet.register("worker")
    skynet.dispatch("lua", function(session, source, cmd, ...)
        print("[worker] received `"..cmd.."`")
        local f = CMD[cmd]
    end)
end)

幾個api的介紹如下。

  1. register(name) 給當前服務起一個字符串名。
  2. dispatch(type, func) 爲 type 類型的消息設定一個處理函數。

回調函數的簽名是這樣:

function (session, source, ...)

其中dispatch的回調函數前兩個參數分別是這樣解釋。

  1. session是爲了確保能將消息處理結果對應到某條消息,就像是服務器收到同一個客戶端的2條網絡請求,一條請求js一條請求css,如果誰先處理完誰就返回的話,可能css的請求就收到了js的內容。
  2. source是消息的來源,是一個整數id。

後面的 cmd 參數其實也屬於變長參數的一部分,但是一般約定變長參數第一個參數是服務要執行的命令 (RPC的感覺),所以就給了個 cmd 的名字。變長參數剩餘的部分就是處理函數的參數了。

當然用其他處理方法也沒問題,只是常用模式。

最終結果

[:00000001] LAUNCH logger
[:00000002] LAUNCH snlua bootstrap
[:00000003] LAUNCH snlua launcher
[:00000004] LAUNCH snlua cdummy
[:00000005] LAUNCH harbor 0 4
[:00000006] LAUNCH snlua datacenterd
[:00000007] LAUNCH snlua service_mgr
[:00000008] LAUNCH snlua main
[:00000009] LAUNCH snlua myservice/msg_dispatcher
[:0000000a] LAUNCH snlua myservice/worker
[:00000008] KILL self
[:00000002] KILL self
[room_mgr] received `say` from `10`
Hello world!
[room_mgr] received `say` from `10`
Hello world!
[room_mgr] received `say` from `10`
Hello world!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章