【从零开始学Skynet】实战篇《球球大作战》(五):gateway代码设计(中)

news2024/10/7 20:34:11

1、编码和解码

        我们来实现两个辅助方法str_unpackstr_pack,用于消息的解码和编码。

(1)str_unpack代码

local str_unpack = function(msgstr)
    local msg = {}

    while true do
        local arg, rest = string.match( msgstr, "(.-),(.*)")
        if arg then
            msgstr = rest
            table.insert(msg, arg)
        else
            table.insert(msg, msgstr)
            break
        end
    end
    return msg[1], msg
end

str_unpack是一个解码方法:

  • 参数msgstr代表消息字符串。
  • 内部是个循环结构,每次循环都由string.match匹配逗号前的字符。

例如:传入的msgstr为“login, 101, 134”,则匹配后arg的值为“login”、rest的值“101,134”;               传入的msgstr为“101, 134”,则匹配后arg的值为“101”、rest的值为“134”。

  • 每次取值后,它会把参数插入msg表,msg表用作协议对象,方便后续取值。
  • str_unpack会返回两个值,第一个值msg[1]是协议名称(协议对象第一个元素),第二个值即为协议对象

如下图所示:

        图中msgstr的值为“login,101,134”。第一个返回值cmd是字符串“login”,第二个返回值msg是一个Lua表。

 (2)str_pack代码

local str_pack = function(cmd, msg)
    return table.concat( msg, ",").."\r\n"
end

str_pack实现了与str_unpack相反的功能,如下图所示:

它将协议对象转换成字符串,并添加分隔符“\r\n”

 2、消息分发

 消息处理方法process_msg如下代码所示:

local process_msg = function(fd, msgstr)
    local cmd, msg = str_unpack(msgstr)
    skynet.error("recv "..fd.." ["..cmd.."] {"..table.concat( msg, ",").."}")

    local conn = conns[fd]
    local playerid = conn.playerid
    --尚未完成登录流程
    if not playerid then
        local node = skynet.getenv("node")
        local nodecfg = runconfig[node]
        local loginid = math.random(1, #nodecfg.login)
        local login = "login"..loginid
		skynet.send(login, "lua", "client", fd, cmd, msg)
    --完成登录流程
    else
        local gplayer = players[playerid]
        local agent = gplayer.agent
		skynet.send(agent, "lua", "client", cmd, msg)
    end
end

虽然代码只有十多行,但还是有点复杂,可通过如下四个部分理解这个方法:

1、消息解码

    通过str_unpack解码消息,相关变量的含义如下。

  • msgstr:切分后的消息,如“login,101,123”。  
  • cmd:消息名,如login。   
  • msg:消息对象,如Lua表{[1]="login", [2]="101", [3]="123"}。         

2、 如果尚未登录

     对于代码“if not playerid”为真的部分,程序将随机选取同节点的一个登录服务器转发消息,相关变量的含义如下。

  • conn:定义的连接对象。
  • playerid:如果完成登录,那么它会保存着玩家id,否则为空。
  • node:中配置文件的节点名,如“node1”。
  • nodecfg:中配置文件的节点配置,如{gateway={...},login={..}}。
  • loginid:随机的login服务编号。
  • login:随机的login服务名称,如“login2”。

3、 如果已登录

   将消息转发给对应的agent,相关变量的含义如下。

  • gpalayer:定义的gateplayer对象。
  • agent:该连接对应的代理服务id。

4、client消息

        消息转发使用了skynet.send(srv,"lua","client", ...)的形式,其中的client是自定义的消息名(skynet中的概念,指服务间传递的消息名字,它与cmd的区别是cmd是客户端协议的名字)。在我们之前封装好的service模块中,loginagent可以用s.resp.client接收转发的消息,再根据cmd做不同处理。

         下图是process_msg方法的示意图,gateway收到客户端协议后,如果玩家已登录,它会将消息转发给对应的代理(阶段③);如果未登录,gateway会随机选取一个登录服务器,并将消息转发给它处理。gateway保持着轻量级的功能,它只转发协议,不做具体处理。

 

         读者可以先屏蔽掉process_msg中分发消息的代码,用telnet等客户端测试gateway能否正常工作。由于在telnet换行即为输入分隔符“\r\n”,因此直接用换行分割消息即可。

 3、发送消息接口

        gateway将消息传给loginagentloginagent也需要给客户端回应。比如,客户端发送登录协议,login校验失败后,要给客户端回应“账号或密码错误”,这个过程如下图所示,它先将消息发送给gateway(阶段③),再由gateway(阶段④)转发。

 下面编写login给客户端发送消息的代码。

(1)send_by_fd代码:

s.resp.send_by_fd = function(source, fd, msg)
    if not conns[fd] then
        return
    end

    local buff = str_pack(msg[1], msg)
    skynet.error("send "..fd.." ["..msg[1].."] {"..table.concat( msg, ",").."}")
	socket.write(fd, buff)
end

        send_by_fd方法用于login服务的消息转发,功能是将消息发送到指定fd的客户端。它先用str_pack编码消息,然后使用socket.write将它发送给客户端。

  • 参数source:消息发送方,比如来自“login1”,
  • 参数fd和:客户端fd
  • 参数msg:消息内容。

 (2)send代码:

s.resp.send = function(source, playerid, msg)
	local gplayer = players[playerid]
    if gplayer == nil then
		return
    end
    local c = gplayer.conn
    if c == nil then
		return
    end
   
    s.resp.send_by_fd(nil, c.fd, msg)
end

        send方法用于agent的消息转发,功能是将消息发送给指定玩家id的客户端。它先根据玩家id(playerid)查找对应客户端连接,再调用send_by_fd发送。

        这两个接口会在后续实现login和agent时调用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/415861.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【web自动化测试】

文章目录web自动化测试第一章 web自动化入门1.什么是自动化?1.1 优点2.什么是自动化测试?2.1 自动化测试能解决什么问题?2.2 自动化相关知识2.2.1优点2.2.2 误区2.3 自动化测试分类3.什么是Web自动化测试?3.1 什么Web项目适合做自…

Flutter 了解 Element

一 Element 概念 这个玩意的概念。到底是什么 ? 官方解释是在树中特定位置的实例。 二 继承关系 element 有 ComponentElement 和 RenderObjectElement 之分 1 ComponentElement class StatelessElement extends ComponentElement class StatefulElement extend…

计及调度经济性的光热电站储热容量配置方法

目录 1 主要内容 目标函数 光热电站能量传递过程 2 部分程序 3 程序结果 4 程序链接 1 主要内容 该程序复现《计及调度经济性的光热电站储热容量配置方法》模型,综合考虑火电机组发电成本、光热发电并网消纳的环境效益和运行维护成本、系统旋转备用成本等调度…

rk3568点亮LCD(RGB)

rk3568 Android11/12 调试 RGB 屏 RGB一般是指RGB色彩模型(RGB color model),是工业界的一种颜色标准。RGB接口占用的资源较多,所以这个接口的LCD刷新率非常快,软件控制也比较简单。缺点是控制需要增加电路,软件初始化需要增加程…

【BOM浏览器对象模型】

BOM浏览器对象模型1 本节目标2 BOM概述3 window对象的常见事件3.1 窗口加载事件3.2 调整窗口大小事件4 定时器4.1 两种定时器4.2 setTimeout()定时器4.3 停止setTimeout()定时器4.4 setInterval()定时器4.5 停止setInterval()定时器4.6 this指向问题5 JS执行队列5.1 JS是单线程…

BUUCTF-.htaccess-sql.fuzz-D盾

第七周第一次 目录 WEB [MRCTF2020]你传你🐎呢 ​编辑 [极客大挑战 2019]HardSQL Crypto 萌萌哒的八戒 传统知识古典密码 Misc 假如给我三天光明 后门查杀 WEB [MRCTF2020]你传你🐎呢 文件上传 我们进行尝试 设置一个 1.jpg的一句话木马 G…

RabbitMQ之高级特性

文章目录一、消息确认机制🎉1.1 消息发送确认(生产者)🔹confirm 确认模式🔹return 回退模式🚩1.2 消息接收确认(消费者)🔸none 自动确认🔸auto 异常确认🔸manual 手动确认二、消费端限流 (prefe…

创略科技联合创始人兼总裁杨辰韵:AIGC、隐私计算赋能数字营销的本质是“以客户为中心”丨数据猿专访...

‍数据智能产业创新服务媒体——聚焦数智 改变商业MarTech概念现身已超十年,伴随着企业数字化转型的大背景,中国MarTech市场也迎来了高速发展。据《2022年中国MarTech市场洞察报告》数据显示,2017-2021年,中国 MarTech产业规模从…

H264码流中 SPS PPS SEI 详解

1 客户端抓包 在做客户端视频解码时,一般都会使用Wireshark抓包工具对接收的H264码流进行分析,如下所示: 在这里我们可以看到对解码视频起关键作用的SPS和PPS。 2、双击SPS内容如下: 那么从上面的sps中我们知道图像的宽&#x…

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

万丈高楼平地起,既然这是个“大项目”,就要有大项目的样子,就要有所规划,下面先把项目的目录结构搭起来。 1、目录结构 建议把Skynet框架放到一个文件夹里,把所有自己编写的内容都放到外层的文件夹里。建立如下表所示的…

MySQL运维10-MySQL数据的导入导出

文章目录0、概述1、mysqldump导出数据mysql导入数据1.1、使用mysqldump导出数据1.1.1、使用--tables导出指定表1.1.2、使用--tab选项将表定义文件和数据文件分开导出1.1.3、使用--fields-terminated-by选项定义数据分隔符1.1.4、使用--databases选项导出整个库或多个库1.1.5、使…

Python算法设计 - 蒙特卡洛法

版权声明:原创不易,本文禁止抄袭、转载,侵权必究! 目录一、蒙特卡洛法二、求圆周率π三、Python算法实现四、作者Info一、蒙特卡洛法 蒙特卡洛方法又称统计模拟法,随机抽样技术,是一种随机模拟方法&#x…

pytorch进阶学习(五):神经网络迁移学习应用的保姆级详细介绍,如何将训练好的模型替换成自己所需模型

代码资源和数据集资源使用进阶学习(四)中的代码,大家可以配合食用哟~ pytorch进阶学习(四):使用不同分类模型进行数据训练(alexnet、resnet、vgg等)_好喜欢吃红柚子的博客-CSDN博客…

数据结构之八大排序算法

文章目录一.常见的排序二.插入排序三.希尔排序四.选择排序五.堆排序六.冒泡排序七.快速排序八.归并排序九.计数排序十.排序总结一.常见的排序 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起…

pytorch性能分析工具Profiler

1. Torch Profiler工具介绍 https://zhuanlan.zhihu.com/p/360479566 PyTorch Profiler 是一个开源工具,可以对大规模深度学习模型进行准确高效的性能分析。包括如下等功能: 分析model的GPU、CPU的使用率各种算子op的时间消耗trace网络在pipeline的CPU和GPU的使用情况Profil…

Educational Codeforces Round 146 (Rated for Div. 2) - B. Long Legs(思维 数学)

题目如下: 题目链接 题解 or 思路: 我们可以发现我们有两个可选的入手方向: 1.正推 2.反推 我们可以发现正推似乎看不出来什么东西,而反推可以发现一个性质! 性质如下: 我们假设最终的腿长为 MMM 可以得到…

sql需要注意的地方 以及 云记模块逻辑

标题模糊搜素时 sql语句需要注意的地方 用concat拼; 用户行为 actionName 进入发布云记页面 actionNameview 添加或修改云记 actionNameaddOrUpdate 查询云记详情 actionNamedetail 删除云记 actionNamedelete 分页查询云记列表 …

第05章_数组

第05章_数组 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 本章专题与脉络 1. 数组的概述 1.1 为什么需要数组 需求分析1: 需要统计某公司50个员工的工资情况,例如计…

chatGPT中文版入口-chatGPT不可以用的地区

ChatGPT老出现不可用 如果您在使用ChatGPT时发现它经常不可用,可能是由于以下原因: OpenAI API的服务不稳定。由于技术问题、网络问题或维护(如软件更新)等原因导致OpenAI API服务不稳定,会导致ChatGPT无法使用。 接…

【JSON学习笔记】2.JSON vs XML及JSON的对象和数组

前言 本章介绍JSON vs XML及JSON的对象和数组。 JSON vs XML JSON 和 XML 都用于接收 web 服务端的数据。 JSON 和 XML在写法上有所不同,如下所示: JSON 实例 {"sites": [{ "name":"csdn教程" , "url":&q…