[关闭]
@wsd1 2017-01-19T07:58:05.000000Z 字数 3019 阅读 2565

【专题3】skynet中watchdog,gate,agent调用关系清理(早期json版)

skynet


参考文档

http://cloudwu.github.io/lua53doc/manual.html#6.4.1

https://github.com/cloudwu/skynet/wiki

背景

该分析涉及到我对早期采用json来传递信息的兴趣,因此需要回溯到之前版本。

git checkout 66a0a6e1db0e8dbcb9d9e55d0d4a3c2a31796e08

导出2015年5月份的版本,该版本将采用json作为客户端通讯的基础格式,之后一个版本就换成了sproto的格式了。

设计思路见“对 skynet 的 gate 服务的重构”: http://blog.codingnow.com/2014/04/skynet_gate_lua_version.html

agent.lua

agent.lua中暴露了 “client”和“lua” 两种类型的调用协议。

“client”协议的注册:

skynet.register_protocol {
    name = "client",
    id = skynet.PTYPE_CLIENT,
    ...
}

A. unpack过程使用了cjson解析json串,dispatch函数调用了SIMPLEDB的接口,演示对KV数据库的操作。

B. client协议主要用于socket直接发送给agent,这个在agent发送了“forward”指令给gate之后会发生,见下面:

function CMD.start(gate , fd)
    client_fd = fd
    skynet.call(gate, "lua", "forward", fd)
    send_client "Welcome to skynet"
end

skynet.dispatch("lua", function(_,_, command, ...)
    local f = CMD[command]
    skynet.ret(skynet.pack(f(...)))
end)

agent.lua中lua协议,仅仅实现了一个“start”的指令,输入参数是 gate地址 和 client的fd。

该指令在watchdog.lua中被调用。

watchdog.lua

function CMD.start(conf)
    skynet.call(gate, "lua", "open" , conf)
end

function SOCKET.open(fd, addr)
    agent[fd] = skynet.newservice("agent")  --这里引导了agent服务
    skynet.call(agent[fd], "lua", "start", gate, fd)
end

...

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
        ...
        end
    end)

    gate = skynet.newservice("gate")    --可见,gate服务在 watchdog中被引导
end)

分析:
watchdog模块中首先引导了“gate”服务。另外实现了一个名称为“open”的“lua”协议接口。
这就调用了agent.lua中那个“start”指令,实施forward操作。

gate.lua

function MSG.open(fd, msg)
    if client_number >= maxclient then
        socketdriver.close(fd)
        return
    end
    local c = {
        fd = fd,
        ip = msg,
    }
    connection[fd] = c
    client_number = client_number + 1
    skynet.send(watchdog, "lua", "socket", "open", fd, msg)
end

...

skynet.register_protocol {
    name = "socket",
    id = skynet.PTYPE_SOCKET,   -- PTYPE_SOCKET = 6
    unpack = function ( msg, sz )
        return netpack.filter( queue, msg, sz)
    end,
    dispatch = function (_, _, q, type, ...)
        queue = q
        if type then
            MSG[type](...)
        end
    end
}

分析:

gate.lua中注册了socket协议接口,意味着会接受 skynet_socket.c中发送的socket事件。

在外部连接接入时会进而调用了 MSG.open,细节请参见“skynet之lua版本的gate_service分析”。而MSG.open又会调用watchdog "lua"协议 "socket"类型 "open"命令。

main.lua

为了说明问题,还应该看一下main.lua

local watchdog = skynet.newservice("watchdog")
skynet.call(watchdog, "lua", "start", {
    port = 8888,
    maxclient = max_client,
    nodelay = true,
})

结论

至此,全部的调用流程理顺,如下:
main.lua 引导了 watchdog,并且调用其start接口

main.lua:

  1. local watchdog = skynet.newservice("watchdog")
  2. skynet.call(watchdog, "lua", "start", {
  3. port = 8888,
  4. maxclient = max_client,
  5. nodelay = true,
  6. })

watchdog引导了gate.lua,之后open gate:

watchdog:

  1. gate = skynet.newservice("gate")
  2. ...
  3. skynet.call(gate, "lua", "open" , conf)

gate开始接受socket的事件,其中连接接入时,调用了watchdog open命令:

gate.lua

  1. function MSG.open(fd, msg)
  2. ...
  3. local c = {
  4. fd = fd,
  5. ip = msg,
  6. }
  7. ...
  8. skynet.send(watchdog, "lua", "socket", "open", fd, msg)
  9. end

进而又引导了agent,调用其start命令:

watchdog.lua:
function SOCKET.open(fd, addr)
    agent[fd] = skynet.newservice("agent")  --这里引导了agent服务
    skynet.call(agent[fd], "lua", "start", gate, fd)
end

agent接受start命令后,便会对gate发送forward指令,进而socket会开始向其发送client协议的消息:

agent.lua:
function CMD.start(gate , fd)
    client_fd = fd
    skynet.call(gate, "lua", "forward", fd)
    send_client "Welcome to skynet"
end

agent拿到fd便可以直接发送消息给client。

20160213 春节假期最后一天,独在住处。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注