啟動服務
local skynet = require"skynet"
skynet.start(function ()
-- body
end)
啟動一個服務需要調(diào)用 skynet 的 start 接口,并向其傳入一個啟動函數(shù)墓臭。
定義消息和處理消息
skynet 的服務是用來接收和處理消息的,那么服務會接收什么樣的消息呢粟誓。通常會在傳入的啟動函數(shù)中注冊該服務能夠處理的消息類型定義和分發(fā)方式枷邪。
- register_protocol 用于消息定義
- dispatch 用于消息分發(fā)
local skynet = require"skynet"
local LUACMD = {}
function LUACMD.echo(msg)
return msg
end
local JSONCMD = {}
function JSONCMD.echo(msg)
print_r(json.decode(msg))
return msg
end
skynet.start(function ()
skynet.dispatch("lua", function(session, source, cmd, ...)
local f = assert(LUACMD[cmd])
skynet.ret(skynet.pack(f(...)))
end)
-- 定義新的 json 消息類型
skynet.register_protocol {
name = "json",
id = 20,
pack = function(m)
return json.encode(m)
end,
unpack = function(m)
local msg_str = skynet.tostring(m)
return json.decode(msg_str)
end,
}
-- 分發(fā) json 類型的消息
skynet.dispatch("json", function (session, source, msg)
local cmd,args = assert(msg.cmd), msg.args
skynet.ret(cmd(table.unpack(args)))
end)
end)
以上代碼實現(xiàn)了 lua 、json 兩種類型消息的分發(fā)抖部,其中 lua 是系統(tǒng)已經(jīng)實現(xiàn)定義好的消息類型说贝, json 類型消息是自定義的類型。
自定義的消息類型時慎颗,需提供 name乡恕、id、pack俯萎、unpack 四個信息傲宜。name 和 id 在系統(tǒng)中需唯一,因為系統(tǒng)實現(xiàn)了十多種消息類型占用了前十多個正整數(shù)夫啊,因而將 id 設為 20函卒。pack 和 unpack 分別是消息的編碼和解碼函數(shù)。
所謂解碼撇眯,指當收到一個服務收到一個該類型的消息之后报嵌,首先會經(jīng)過 unpack 處理一遍。好比收到的 json
消息實為 json 字符串熊榛,需經(jīng)過 json.decode 成 lua 類型數(shù)據(jù)以便使用锚国。
類似的方式,當從該服務發(fā)送一條 json 消息給其他服務時来候,也會使用 pack 進行 json.encode 處理一下才會變?yōu)?json 格式字符串跷叉。當然該其他服務也需實現(xiàn)了能處理 json 消息才好。
實現(xiàn)服務間通信
大多數(shù)情況下,僅使用 lua 消息就可以很好的實現(xiàn)我們的業(yè)務云挟,因而一個服務的樣子大致是這樣:
local skynet = require"skynet"
local CMD = {}
function CMD.echo(msg)
return msg
end
function CMD.foo()
return "bar"
end
skynet.start(function ()
skynet.dispatch("lua", function( session, source, cmd, ... )
local f = assert(CMD[cmd])
skynet.ret(skynet.pack(f(...)))
end)
end)
按這個方式梆砸,模擬兩個 玩家服務 通過 聊天服務 互發(fā)消息。
chatd.lua
local skynet = require"skynet"
require"skynet.manager"
local agents = {}
local mt = {}
mt.__index = mt
function mt.msg(from,to,msg)
local to_agent = assert(agents[to])
skynet.send(to_agent,"lua","msg",from,msg)
end
function mt.add_agent(name,agent)
agents[name] = agent
end
skynet.start(function ()
skynet.dispatch("lua", function(session,source,cmd,...)
local f = assert(mt[cmd])
return skynet.ret(skynet.pack(f(...)))
end)
skynet.register(".chatd")
end)
agent.lua
local skynet = require"skynet"
local name
local mt = {}
mt.__index = mt
function mt.msg(from, msg)
skynet.error(string.format("agent [%s] get msg:[%s] from agent[%s]", name,msg,from))
end
function mt.send(from,to,msg)
local chatd = skynet.localname(".chatd")
skynet.send(chatd,"lua","msg",from,to,msg)
end
function mt.setname(agent_name)
name = agent_name
end
skynet.start(function (agent_name)
name = agent_name
skynet.dispatch("lua", function(session,source,cmd,...)
local f = assert(mt[cmd])
return skynet.ret(skynet.pack(f(...)))
end)
end)
main.lua
local skynet = require"skynet"
skynet.start(function()
local chatd = skynet.newservice("chatd") -- 啟動聊天服務
local tom = skynet.newservice("agent") -- 啟動玩家并設置名稱為tom
skynet.call(tom,"lua","setname","tom")
local jim = skynet.newservice("agent") -- 啟動玩家并設置名稱為jim
skynet.call(jim,"lua","setname","jim")
skynet.call(chatd,"lua","add_agent","tom",tom) -- 把 tom 注冊到 聊天服
skynet.call(chatd,"lua","add_agent","jim",jim) -- 把 jim 注冊到 聊天服
skynet.send(tom,"lua","send","tom","jim","foo") -- 通知 tom 讓其向 jim 發(fā)消息
skynet.send(jim,"lua","send","jim","tom","bar") -- 通知 jim 讓其向 tom 發(fā)消息
skynet.exit()
end)
執(zhí)行
skynet/skynet etc/config
輸出
[: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 chatd
[:0000000a] LAUNCH snlua agent
[:0000000b] LAUNCH snlua agent
[:00000008] KILL self
[:0000000b] agent [jim] get msg:[foo] from agent[tom]
[:00000002] KILL self
[:0000000a] agent [tom] get msg:[bar] from agent[jim]