前言
- 之前刚看
skynet的时候就一直看skynet example的例子,想想这些例子对于新人来说不妨说是入门的时候必看的,也有必要理清一下流程,以防之后再看,得重新梳理一遍,这边blog不会过多关心api的使用
正文
启动流程
任何程序,都有一个入口程序,而
skynet这个框架的入口是配置在config start里面(只是从框架层面来说,不涉及底层),example的入口程序是main.lua不是登录的main.lua哦,其实就是注意下lua的搜索路径。代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22local skynet = require "skynet"
local sprotoloader = require "sprotoloader"
local max_client = 64
skynet.start(function()
skynet.error("Server start")
skynet.uniqueservice("protoloader")
if not skynet.getenv "daemon" then
local console = skynet.newservice("console")
end
skynet.newservice("debug_console",8000)
skynet.newservice("simpledb")
local watchdog = skynet.newservice("watchdog")
skynet.call(watchdog, "lua", "start", {
port = 8888,
maxclient = max_client,
nodelay = true,
})
skynet.error("Watchdog listen on", 8888)
skynet.exit()
end)这部分代码作用如下
- 启动
protoloader服务 - 是否启动
console服务 - 启动
debug_console服务 - 启动
simpledb服务 - 启动
watchdog服务
- 启动
通信协议服务
- wait…
看门狗服务
skynet.start初始化服务,并启动网关。watchdog里的变量gate保存的是网关服务的地址
网关服务
调用
gateserver.start(handler)启动网关服务注册
socket消息的解包方式和回调函数1
2
3
4
5
6
7
8
9
10
11
12
13skynet.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
}- 一旦有
socket消息,就会调用unpack的分包,再调用到MSG的回调函数。为啥需要queue?因为这个是处理粘包时候的逻辑。 - 粘包的时候会使用
dispatch_queue()去处理分包,从queue里面pop一个元素
- 一旦有
使用
init()初始化服务
这个时候
main.lua会callwatchdog服务,watchdog服务会call网关服务监听套接字,执行网关服务的CMD.open,监听配置的地址和端口,这个时候逻辑就执行完了,不会阻塞在listen里的,待研究…客户端开始连接套接字,这个时候
gateserver.lua会使用socketdriver.start,判断一下gate模块是否有open函数,开始回调,gate模块记录下watchdog服务的地址。之后socket的第一条消息是open,也就是调用到MSG.open(fd,msg)会做一些限流操作,也就是连接客户端的上限,设置connect[fd] = true表示客户端已经连接上网关模块了。然后回调到gate模块的connect,gate模块会保存一份connect[fd] = {fd = fd , ip = addr},再send一条消息到watchdog服务上,告诉watchdog客户端的套接字和地址,这个时候watchdog开始new一个agent服务,也就是玩家服务,watchdog变量agent[fd] = 玩家服务地址,agent服务初始化的时候注册了一个客户端的消息,定义了解包和回调函数。watchdog服务再call玩家服务,这样子玩家服务就保存了套接字的地址和网关模块的地址和watchdog的地址。这个时候可以执行心跳包逻辑,再call网关服务回调forward(source, fd, client, address),这个时候网关模块完善了connect[fd] = {fd = fd ,ip = addr, client = 0, c.agent = source}而forwarding[c.agent] = c这样就能根据agent的地址找到fd,根据fd能知道对应agent,这个时候启动gateserver开始启动收发数据,也就是gateserver.openclient,也就是启动socketdriver.start(fd)这个时候才是建立了和客户端的连接再讲一下消息处理,也就是
MSG.data,会回调到gate的message(fd, msg, sz),这个时候会取出fd对应的agent使用skynet.redirect()伪造是客户端直接发给玩家的包。