@wsd1
2017-01-19T07:58:05.000000Z
字数 3019
阅读 2565
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中暴露了 “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中被调用。
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操作。
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
local watchdog = skynet.newservice("watchdog")
skynet.call(watchdog, "lua", "start", {
port = 8888,
maxclient = max_client,
nodelay = true,
})
至此,全部的调用流程理顺,如下:
main.lua 引导了 watchdog,并且调用其start接口
main.lua:
local watchdog = skynet.newservice("watchdog")
skynet.call(watchdog, "lua", "start", {
port = 8888,
maxclient = max_client,
nodelay = true,
})
watchdog引导了gate.lua,之后open gate:
watchdog:
gate = skynet.newservice("gate")
...
skynet.call(gate, "lua", "open" , conf)
gate开始接受socket的事件,其中连接接入时,调用了watchdog open命令:
gate.lua
function MSG.open(fd, msg)
...
local c = {
fd = fd,
ip = msg,
}
...
skynet.send(watchdog, "lua", "socket", "open", fd, msg)
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 春节假期最后一天,独在住处。