宏宏宏

由于 C++ 是静态语言,不能像 js 一样通过函数名字符串来直接执行函数,所以将 messageId 映射到可执行函数的复杂性大大提升;KBEngine 使用了一系列精巧的「宏」来解决这个问题。

为了叙述方便,我把需要通过 messageId 来映射执行的函数称为「协议函数」,以区分普通的函数。

loginapp 的宏,统一在 loginapp_interface_macros.h 中声明,在 loginapp_interface.h 中使用。我把 loginapp_interface.h 进行简化,只保留两个函数:importClientMessage,login。

可以看到,上面截图分为 3 个部分

  • 第 5 、14 行是一个完整的宏
  • 第 8 行是将 importClientMessages 转化为「协议函数」的宏
  • 第 11、12 行是将 login 转化为「协议函数」的宏

namespace LoginappInterface

上图是将本文第一张图 5、14 行宏展开后的代码,这对 BEGIN/END 宏,不光是定义了一个 namespace,更重要的是,声明了 messageHandlers,这里面就存放了所有映射好的「协议函数」

importClientMessages

上图是将本文第一张图中第 8 行展开后的代码,由几个重要的逻辑组成:

  • 30~38 行,声明了一个 MessageHandler 的派生类,这个类的 handle 函数,是个 virtual 函数,执行的就是 Loginapp::importClientMessages。(KBEngine 架构的 loginapp 是单例,所以这里才能这么玩,否则没法对应到想要执行的函数所在对象)
  • 40~45 行,将调用 messangeHandlers.add 函数,完成 messangeId 到 importClientMessagesLoginappMessagehandler0 类对象的映射;
    此后,就可以通过 messageId 找到一个 MessangeHandler 对象指针,然后执行他的 handle 函数,由于这是 virtual 函数,真正执行的就是 importClientMessagesLoginappMessagehandler0 中的 handle 函数,也就是 Loginapp::importClientMessages 函数。
  • 47 行,保存添加过映射关系的 MessangeHandlers;这个主要是为了其他组件调用,如 baseapp 可以通过(*pBundle).newMessage( Loginapp::importClientMessages);  这样的形式调用到这个函数
  • 49~69 行 importClientMessages 函数的参数对象,ARGS0 表示 importClientMessages 函数不需要参数。

login

上图是将本文第一张图中第 11、12 行展开后的代码,由几个重要的逻辑组成:

  • 28 行,使用 "Loginapp::login" 作为 messageHandlers.pushExposedMessage 的参数,即这个函数将会被导出到客户端,以便客户端调用。
  • 30~68 行,与前面逻辑基本一样,这里不再解释。
  • 主要看两个图的第 37 行的区别,可以看到,LOGINAPP_MESSAGE_DECLARE_ARGS0 宏展开后,这行除了 Channel,没有其他参数;LOGINAPP_MESSAGE_DECLARE_STREAM 宏展开后,除了 Channel,还有一个 MemoryStream 参数,表示这个函数的参数需要从流中读取。

MessageHandlers::add

add 函数,将"Loginapp::login" 形式的函数名转成 messageId,并与 MessageHandler* 建立映射关系。

上图,150~171 行,先通过 FixedMessage 判断("Loginapp::login")函数名是否在 res/server/messages_fixed.xml 中声明过,如果声明过,就取声明的 id 作为 messageId,否则就循环找到一个未被使用的 id。

上图,180 行建立 messageId 到 MessageHandler* 的映射。msgHandlers_ 是一个 map。

上图,50 行,可以看到 FixMessages 加载的配置文件地址,就是我们一直提到的 messages_fixed.xml。

协议执行

通过上面的宏,我们可以看到 messageId -> 「协议函数」的映射关系已经建立起来,那么这个在什么时候回被调用到呢?

上图是 login 函数的调用堆栈,我们来看一下 Loginapp::handleMainTick 函数

可以看到,112 行的参数是 &LoginappInterface::messageHandlers,也就是在宏里已经填好 messageId -> 「协议函数」映射关系的全局变量。

真正的执行逻辑,在 PacketReader::processMessages 函数里。

如上图,先在 81 行取到 messageId,然后在 85 行,在 messageHandlers 里 find (简单的 map 的查找即可)到对应的 MessageHandler,再调用 handle 函数,按我们前面的分析,handle 函数里面会调用到 messageId 对应的 「协议函数」。

至此,整个 loginapp 服务器端协议从构建到解析执行的整个过程解释完成。

后记

KBEngine 支持的几种宏说明

    • LOGINAPP_MESSAGE_DECLARE_ARGS0,  「协议函数」有 0 个参数
    • LOGINAPP_MESSAGE_DECLARE_ARGS1,  「协议函数」有 1 个参数
    • LOGINAPP_MESSAGE_DECLARE_ARGS2,  「协议函数」有 2 个参数
    • LOGINAPP_MESSAGE_DECLARE_STREAM,「协议函数」参数为 MemoryStream
    • LOGINAPP_MESSAGE_EXPOSED,「协议函数」将被暴露给客户端,即会在 importClientMessages 中发送给客户端

KBEngine 服务器端-loginapp-协议构建、解析执行详细介绍的更多相关文章

  1. HTML页面加载和解析流程详细介绍

    浏览器加载和渲染html的顺序 1. IE下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的. 2. 在渲染到页面的某一部分时,其上面的所有部分都已经下载完成(并不是说所有相关联的元 ...

  2. Http协议中Cookie使用详细介绍

    Cookie总是保存在客户端中,按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie.内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的.硬盘Cookie ...

  3. https协议了解,以及相关协议的解析

    HTTPS简介 HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版. ...

  4. TCP协议 状态解析和状态统计

    一.三次握手和四次挥手 1.建立连接(三次握手)   (1)服务器会处于listen状态,客户端发送一个带SYN标志的TCP报文到服务器.   (2)服务器端回应客户端的请求,这是三次握手中的第2个报 ...

  5. 【Win10 UWP】URI Scheme(一):Windows Store协议的解析和使用

    协议是Windows Phone和Windows Store应用的一个重要特点,可以做到在不同应用之间进行互相呼起调用.小小协议,学问大着呢.我打算写几篇关于协议在UWP中使用的文章. 这一讲的主要对 ...

  6. 实验六 TLS协议报文解析

    一.实验目的 1.访问一个https://....的网站,捕TLS包并分析报文序列. 2.分析连接建立的完整过程,如:TCP三次握手.SSL安全连接,使用TLS协议连接.协商过程,加密传送的状态.TC ...

  7. 使用 C# 实现 CJ-T188 水表协议和 DL-T645 电表协议的解析与编码

    一.协议的定义 要对某种协议进行编解码操作,就必须知道协议的基本定义,首先我们来看一下 CJ/T188 的数据帧定义(协议定义),了解请求数据与响应数据的基本结构. 1.1 CJ/T188 水表通讯协 ...

  8. 基于部标1078视频协议和苏标Adas协议构建主动安全平台

    苏标本身仍然是基于部标808协议的基础上递增起草的,苏标协议是包容808协议的, 不能脱离808协议而独立存在的, 主要基于<JT/T 796 道路运输车辆卫星定位系统平台技术要求>.&l ...

  9. 转:Http协议中Cookie详细介绍

    Http协议中Cookie详细介绍 Cookie总是保存在客户端中,按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie.内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了, ...

随机推荐

  1. JQuery中event的preventDefault和stopPropagation介绍

    event.preventDefault()阻止默认事件行为的触发. event.stopPropagation()防止事件冒泡到DOM树上,也就是不触发的任何前辈元素上的事件处理函数. <!D ...

  2. 创建 StyledMapType 地图样式

    您可以通过创建 StyledMapType 并向构造函数传递特征和样式器信息,新建作为样式应用对象的地图类型.此方法不会影响默认地图类型的样式. 如需新建地图类型: 创建您的样式数组.请参阅“地图特征 ...

  3. Unix环境高级编程(五)进程环境

    本章主要介绍了Unix进程环境,包含main函数是如何被调用的,命令行参数如何传递,存储方式布局,分配存储空间,环境变量,进程终止方法,全局跳转longjmp和setjmp函数及进程的资源限制. ma ...

  4. nodejs request gb2312乱码的问题

    http://www.cnblogs.com/linka/p/6658055.html https://cnodejs.org/topic/53142ef833dbcb076d007230 // np ...

  5. CSS2中的伪类与伪元素

    CSS 伪类用于向某些选择器添加特殊的效果. 我们最常见的就是有超链接的时候,向下面这样 a:link {color: #FF0000} /* 未访问的链接 */ a:visited {color: ...

  6. 强制删除一个Windows服务

    一个挂起的服务如下图所示,该服务相关的所有按钮都被禁用,包括启动.停止.暂停和恢复. 要停止这个服务,首先记住这个服务的名称,在这里是 ‘EntropySoftCFS’. 然后打开命令行窗口,运行 s ...

  7. macbook基本配置

    1.安装iterm2, 2.安装搜狗输入法, 3.安装迅雷, 4.安装homebrew 5.安装新版的gcc,bash等等,及升级配置文件.

  8. [na]交换技术知识点-提纲

    vlan - trunk - vtp(vtp prune) stp portfast rootgurd bpduguard bpdufilter uplinkfast backbonfast loop ...

  9. POJ 2553 The Bottom of Graph 强连通图题解

    Description We will use the following (standard) definitions from graph theory. Let V be a nonempty ...

  10. git 从远程git服务上拉代码 git服务器非默认端口

    从服务器上拉代码有如下报错: fatal: Not a git repository (or any of the parent directories): .git 初始代本地版本库: [root@ ...