[skynet] skynet.dispatch有啥用? skynet.register_protocol又是干啥的?

skynet.start里写skynet.dispatch有啥用?
有些地方的skynet.register_protocol,那又是干啥用的?
一脸懵逼啊
懵逼? 不用懵逼,下面我来捋一捋

关于typename叫做"lua"的消息分发

先上代码:

skynet.start(function()
    skynet.dispatch("lua", function(session, source, cmd, subcmd, ...)
        if cmd == "socket" then
            local f = SOCKET[subcmd]
            f(...)
            -- socket api don't need return
        else
            local f = assert(CMD[cmd])
            skynet.ret(skynet.pack(f(subcmd, ...)))
        end
    end)

    gate = skynet.newservice("gate")
end)

这是skynet源码中,examplewatchdog的一个代码片段.
当有人用skynet.send(addr, "lua", ...)或者skynet.call(addr, "lua", ...)之类的方法呼叫, skynet就会用skynet.dispatch("lua", func)里的func来处理.
上面send/call/dispatch里的"lua"就是typename,也就是skynet里proto[typename]key,这样讲你可能有点晕,那么放一段代码

function skynet.send(addr, typename, ...)
    local p = proto[typename]
    return c.send(addr, p.id, 0 , p.pack(...))
end

上面这段是skynetsend的源码, 可以看到通过typenameproto这个table里去找东西.
那么这个proto是在哪里赋值的呢?来看两段代码:

    local REG = skynet.register_protocol

    REG {
        name = "lua",
        id = skynet.PTYPE_LUA,
        pack = skynet.pack,
        unpack = skynet.unpack,
    }
function skynet.register_protocol(class)
    local name = class.name
    local id = class.id
    assert(proto[name] == nil and proto[id] == nil)
    assert(type(name) == "string" and type(id) == "number" and id >=0 and id <=255)
    proto[name] = class -- 用name注册
    proto[id] = class -- 用id注册
end

第一段是注册,第二段是注册的实现.
可以看到skynet在初始化的时候,就注册了protokeylua的操作了, 但没有dispath的实现, 那么这就需要在服务启动或启动后的某个时刻注册一下.放在skynet.start里进行注册是个不错的时机.
所以就有下面的操作

skynet.start(function()
    skynet.dispatch("lua", function(session, source, cmd, subcmd, ...)
        -- 一些操作
    end)
    -- 一些操作
end)

那么如果我不想用"lua"作为key可以吗? 当然可以.


自定义typename,注册及实现消息分发

自定义typenameskynet在初始化里定义有个叫"lua"typename是一样的.
下面我直接给两份代码:

local skynet = require "skynet"
local my_id = 101

-- 注册消息, 否则要不然发不出去, 因为没有注册过.
skynet.register_protocol {
    name = "eat_toufu", -- 自定义的名字
    id = my_id,  -- 不要重复使用skynet已经使用的,以防万一(1~12都已经被使用了)
    pack = skynet.pack, --可以使用各种各样的pack方法, 这里使用skynet的方案, 不定义的话,就发不出去了.
    -- unpack = skynet.unpack, -- 如果不接收的话, 不写也可以
    -- dispatch = function() end -- 如果不接收的话, 不写也可以
}

skynet.start(function ()
    local myserver= skynet.newservice("myserver")
    skynet.send(myserver,"eat_toufu","toufu","delicious") -- 这里使用了自定义的typename [eat_toufu]
    skynet.exit()
end)
local skynet = require "skynet"
local my_id = 101

skynet.register_protocol {
    name = "eat_toufu",-- 自定义的名字
    id = my_id ,
    -- pack = skynet.pack,  -- 如果不发送的话, 不写也可以
    unpack = skynet.unpack, --可以使用各种各样的unpack方法, 这里使用skynet的方案, 不定义的话,就收不到了.
    dispatch = function (fd, from, type, ...) --这就是接收的地方.
        skynet.error("--->",fd, from, type,...)
    end
}

skynet.start(function() end)

第一段代码是发送方, 第二段是接收处理方.
主要就是在register_protocol里的dispatch实现.
这里的dispatchskynet.dispatch是类似的,结果都是在告诉skynet,针对对应的消息,我要注册一个响应的方法去处理,不同之处在于:

  • skynet.dispatch是针对已经在skynet.register_protocol里注册过的消息名,注册响应方法, 比如"lua".
  • skynet.register_protocol里的dispatch是在注册新的自定义消息时, 同时实现响应方法.

好了, 要讲的也讲的差不多了, 如果有错的地方, 欢迎指出, 谢谢 :)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容