美文网首页
[skynet] skynet.dispatch有啥用? sky

[skynet] skynet.dispatch有啥用? sky

作者: 吃豆腐不吐豆腐皮 | 来源:发表于2021-09-07 16:13 被阅读0次

    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是在注册新的自定义消息时, 同时实现响应方法.

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

    相关文章

      网友评论

          本文标题:[skynet] skynet.dispatch有啥用? sky

          本文链接:https://www.haomeiwen.com/subject/svfpwltx.html