literwave game.

skynet example main分析

Word count: 946Reading time: 3 min
2022/12/11

前言

  • 之前刚看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
      22
      local 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
        13
        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
        }
        • 一旦有socket消息,就会调用unpack的分包,再调用到MSG的回调函数。为啥需要queue?因为这个是处理粘包时候的逻辑。
        • 粘包的时候会使用dispatch_queue()去处理分包,从queue里面pop一个元素
      • 使用init()初始化服务

    • 这个时候main.luacall watchdog服务,watchdog服务会call网关服务监听套接字,执行网关服务的CMD.open,监听配置的地址和端口,这个时候逻辑就执行完了,不会阻塞在listen里的,待研究…

    • 客户端开始连接套接字,这个时候gateserver.lua会使用socketdriver.start,判断一下gate模块是否有open函数,开始回调,gate模块记录下watchdog服务的地址。之后socket的第一条消息是open,也就是调用到MSG.open(fd,msg)会做一些限流操作,也就是连接客户端的上限,设置connect[fd] = true表示客户端已经连接上网关模块了。然后回调到gate模块的connectgate模块会保存一份 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,会回调到gatemessage(fd, msg, sz),这个时候会取出fd对应的agent使用skynet.redirect()伪造是客户端直接发给玩家的包。

CATALOG
  1. 1. 前言
  2. 2. 正文