skynet 笔记续

启动服务

local skynet = require"skynet"

skynet.start(function ()
       -- body
end)

启动一个服务需要调用 skynet 的 start 接口,并向其传入一个启动函数。

定义消息和处理消息

skynet 的服务是用来接收和处理消息的,那么服务会接收什么样的消息呢。通常会在传入的启动函数中注册该服务能够处理的消息类型定义和分发方式。

  1. register_protocol 用于消息定义
  2. dispatch 用于消息分发
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,
    }

    -- 分发 json 类型的消息
    skynet.dispatch("json", function (session, source, msg)
        local cmd,args = assert(msg.cmd), msg.args
        skynet.ret(cmd(table.unpack(args)))
    end)

end)

以上代码实现了 lua 、json 两种类型消息的分发,其中 lua 是系统已经实现定义好的消息类型, json 类型消息是自定义的类型。

自定义的消息类型时,需提供 name、id、pack、unpack 四个信息。name 和 id 在系统中需唯一,因为系统实现了十多种消息类型占用了前十多个正整数,因而将 id 设为 20。pack 和 unpack 分别是消息的编码和解码函数。

所谓解码,指当收到一个服务收到一个该类型的消息之后,首先会经过 unpack 处理一遍。好比收到的 json
消息实为 json 字符串,需经过 json.decode 成 lua 类型数据以便使用。

类似的方式,当从该服务发送一条 json 消息给其他服务时,也会使用 pack 进行 json.encode 处理一下才会变为 json 格式字符串。当然该其他服务也需实现了能处理 json 消息才好。

实现服务间通信

大多数情况下,仅使用 lua 消息就可以很好的实现我们的业务,因而一个服务的样子大致是这样:

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)

按这个方式,模拟两个 玩家服务 通过 聊天服务 互发消息。

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 发消息
    skynet.send(jim,"lua","send","jim","tom","bar")    -- 通知 jim 让其向 tom 发消息
    skynet.exit()
end)

执行

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]

你可能感兴趣的:(skynet 笔记续)