【从零开始学Skynet】实战篇《球球大作战》(二):结构设计

news/2025/2/14 5:00:55/

        万丈高楼平地起,既然这是个“大项目”,就要有大项目的样子,就要有所规划,下面先把项目的目录结构搭起来。

1、目录结构

        建议把Skynet框架放到一个文件夹里,把所有自己编写的内容都放到外层的文件夹里。建立如下表所示的目录结构:

文件(夹)说明
etc存放服务配置的文件夹
luaclib存放一些C模块(.so文件)
lualib存放Lua模块
service存放各种服务的Lua代码
skynetSkynet框架,我们不会改动Skynet的任何内容。如果后续Skynet有更新,直接替换该文件夹即可
start.sh启动服务器的脚本

    创建完目录结构之后如下图所示:

             service文件夹用于存放各种服务的代码,每个服务的代码都放到一个以服务名称命名的文件夹里。如下图所示:

         服务端会开启gatewayloginagent等多种服务,我们光给每个服务建立对应的文件夹。主服务是节点启动后第一个被加载的服务,用于启动其他各个服务,它比较特殊,我们不给它创建对应的文件夹,而是为它创建一个main.lua文件。

2、配置文件

        更改了目录结构,需要重新编写Skynet的配置文件,让Skynet可以加载项目代码。在etc文件夹下新建文本文件config.node1config.node2,它们代表各个节点的配置。

config.node1中的代码如下所示:

--必须配置
thread = 8 --启用多少个工作线程
cpath = "./skynet/cservice/?.so" --用C编写的服务模块的位置
bootstrap = "snlua bootstrap" --启动的第一个服务
--bootstrap配置项
start = "main" --主服务入口
harbor = 0 --不使用主从节点模式
--lua配置项
lualoader = "./skynet/lualib/loader.lua"
luaservice = "./service/?.lua;" .."./service/?/init.lua;".."./skynet/service/?.lua;"
lua_path = "./etc/?.lua;" .. "./lualib/?.lua;" .. "./skynet/lualib/?.lua;" .. "./skynet/lualib/?/init.lua"
lua_cpath = "./luaclib/?.so;" .. "./skynet/luaclib/?.so"
--后台模式(必要时开启)
--daemon = "./skynet.pid"
--logger = "./userlog"
--节点
node = "node1"

这份配置与Skynet的默认配置没有太大区别,但有一些需要注意的地方,具体如下:

  • 因为Skynet引擎被放置到skynet文件夹下了,所以要重设cpath、lualoader、luaservice、lua_path、lua_cpath的路径;
  • 由于自定义服务位于service文件夹下,因此要修改luaservice配置项,让它搜索该文件夹。按照上面代码的设置,它会依次查找service/[服务名].luaservice/[服务名]/init.lua作为服务的启动文件。如果查找失败,才去搜索skynet提供的服务。
  • 依据代码中lua_path项的配置,当程序需要加载Lua模块时,它会依次查找etc/[模块名].lualualib/[模块名].lua,再查找skynet提供的模块;
  • 自定义环境变量“node”,代表节点名称;
  • 使用cluster集群模式,设置harbor=0
  • 主服务为main,根据luaservice项的配置,skynet会启动service/main.lua作为主服务;
  • config.node2config.node1的内容一样,只是将node="node1"改成了node="node2"

3、主服务           

         先编写个最简单的主服务,用于测试。首先要让系统能启动,后面才好编写功能逻辑。

local skynet = require "skynet"
skynet.start(function()--初始化skynet.error("[start main]")--退出自身skynet.exit()
end)

4、启动脚本

        因为启动脚本的命令很长:“./skynet/skynet./etc/config.node1”,不方便输入,在我们之前创建的start.sh中编写如下所示的代码:

./skynet/skynet ./etc/config.node$1

        在start.sh所在的目录执行“sh start.sh 1”即可启动程序,执行“sh start.sh 2”即可开启第二个节点,方便多了。启动主服务后如下图所示:

倒数第三行的“[start main]”正是主服务打印出的内容,如果能看到此信息,说明启动成功。

5、服务配置

  • 服务端支持横向拓展,每个节点可以开启不同数量的gateway、login,此处需要通过一份配置文件来描述服务端的拓扑结构
  • 各个服务也需要根据这份配置文件来查找其他服务的位置;
  • 比如login服务器需要与agentmgr通信,那么它就需要知道agentmgr在哪个节点,配置文件会提供这个信息;
  • 服务配置还会提供服务所需的一些参数,比如每个gateway监听哪个端口号。

   新建文件etc/runconfig.lua,代码如下所示:

return {--集群cluster = {node1 = "127.0.0.1:7771", node2 = "127.0.0.1:7772",},--agentmgragentmgr = { node = "node1" },--scenescene = {node1 = {1001, 1002},  --node2 = {1003},},--节点1node1 = {gateway = {[1] = {port=8001},[2] = {port=8002},},login = {[1] = {},[2] = {},},},--节点2node2 = {gateway = {[1] = {port=8011},[2] = {port=8022},},login = {[1] = {},[2] = {},},},
}

 代码说明:

  • cluster指明服务端系统包含两个节点,分别为node1node2。各个节点需要通信,其中node1的地址为“127.0.0.1:7771”node2的地址为“127.0.0.1:7772”
  • agentmgr指明全局唯一的agentmgr服务位于node1处;
  • scene指明在node1开启编号为10011002的两个战斗场景服务,语句“node2={1003}”代表在node2开启编号为1003的场景服务。为了方便前期开启单个节点来调试功能,我们先把node2={1003}这行代码注释掉,用时再开启;
  • node1node2描述了各节点的“本地”服务。两个节点分别开启了两个gateway和两个loginnode1处的两个gateway的监听端口分别是80018002node2的是80118012

    下图对代码中各项也做出了解释:

 6、服务测试

        该如何读取这份配置文件呢?我们可以做个简单测试,在./service/main.lua文件中添加两句代码,代码如下所示:

local skynet = require "skynet"
local runconfig = require "runconfig"
skynet.start(function()--初始化skynet.error(runconfig.agentmgr.node)--退出自身skynet.exit()
end)

        在start.sh所在的目录下执行“sh start.sh 1”,主服务应该能把“runconfig.agentmgr.node”的值“node1”打印出来:

         这段代码仅是范例,大家可以根据项目需要自行修改。如果游戏在线人数很多,要配置更多节点,开启更多gateway

        后面的主程序会读取runconfig.lua,决定节点内要启动哪些服务。gateway也会读取它,用于设置监听端口


http://www.ppmy.cn/news/41864.html

相关文章

【springBoot篇1】概念、创建和运行

目录 一、什么是springBoot?为什么要学springBoot springBoot的优点:(5点) 优点1:快速集成框架 优点2:内置了Tomcat容器 优点3:快速部署项目 优点4:少配置,多注解 优点5:支持更…

AD20 原理图设计流程

Altium Designer 20 的原理图设计大致可以分为9个步骤: (1)新建原理图。这是原理图设计的第一步。 (2)图纸设置。图纸设置就是要设置图纸的大小,方向等信息。图纸设置要根据电路图的内容和标准化来进行。…

认证服务---OAuth2.0基本介绍,微博登录整合到实际项目中【下篇】

前言 上一篇简单介绍了它的基本使用,这一篇就粗略说明一下如何在项目中实际应用 1、核心代码 1.1 认证微服务 当你进行了授权之后,跳转到一个新的地址。这个地址应该是你访问接口的地址。在这个接口中完成相应的access_token获取,以及调用…

JavaScript加减乘除方法及运算符号

嗨大家好,我是技术宅小伙。欢迎再次收看文轩解码的加法术教学,今天来到了第4集。同学们已经看了前3集,觉得之前的教学对你有帮助吗?如果有,可以在下面的留言栏里告诉我,顺便也可以提及你们对学习加法术的意…

【ChatGPT】ChatGPT掀起AIGC与AI浪潮

文章目录 前言 一、我为什么要这么做? 二、AI与AIGC 1.AI是什么? 2. AIGC是什么? 2.1 AIGC的优势 2.2 AIGC的劣势 3. AI与AIGC的区别 三、ChatGPT 四、应对措施和改变 1. 找到自己的风格 2. 学习AI的优点 3. 创新型方法 总结​​​​​​​ 前…

四、k8s详细介绍-应用场景

Kubernetes(K8S)是一种开源的容器编排平台,它可以自动化管理容器化应用程序的部署、扩展和管理。K8S具有高度的可扩展性、灵活性和可靠性,因此在各种应用场景中得到广泛应用。本文将介绍K8S的应用场景,包括以下方面: 1.云原生应用 K8S是云原生应用的基石,它为云原生应…

Java多线程基础

目录 一,线程相关概念 1.程序 2.进程 3.线程 4.并发 5.并行 二,线程基本使用 1.创建线程的方法 继承Thread类 实现Runnable接口 三,继承Thread和实现Runnable的比较 四,线程终止 五,常用方法 用户线程和守…

这么好看的客服组件,还是觉得接入ChatGPT,把它放在博客中那就完美了

我们在使用ChatGPT时,它的返回方式是采用流式回复。感觉这个效果不错。之前做的全都是的等全部结果请求完成,再一次性返回给用户。今天就通过流式回复的效果重写之前的程序。 前端 前端采用一个网页版的客服组件,整体的效果如下:…