宏宏宏

由于 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. FA_手工明细增加固定资产(流程)

    2014-06-08 Created By BaoXinjian

  2. FA_固定资产六大业务增加、修改、报废、在建、折旧、盘点概述(概念)

    2014-06-04 Created By BaoXinjian

  3. DBA_实践指南系列8_Oracle Erp R12数据维护模式Adadmin(案例)

    2013-12-08 Created By BaoXinjian

  4. Android studio 使用NDK工具实现JNI编程

    前言: Android开发中常常会使用到第三方的.so库.在使用.so库的时候就要用到JNI编程.JNI是Java Native Interface的缩写.它提供了若干的API实现了Java和其它语言 ...

  5. oracle序列sequence操作汇总(命令)--待续

    1.创建sequence 2.删除sequence 3.查询有哪些sequence select * from user_objects where object_type='SEQUENCE'; 4 ...

  6. Java的spi介绍和简单应用

    1.什么是java的spi SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制. 目前有不少框架用它来做服务的扩展发现, 简单来说,它就是一 ...

  7. [k8s]容器化node-expolore(9100)+cadvisor(8080)+prometheus(9090) metric搜集,grafana展示

    Prometheus 的核心,多维数据模型 传统监控工具统计数据方式 指标多 - 需求1,统计app1-3,的(总)内存,则定义3个指标 container.memory_usage_bytes.we ...

  8. 【Android】20.0 第20章 音频、视频、拍照、语音合成

    分类:C#.Android.VS2015: 创建日期:2016-03-11 一.简介 Android提供了常见的多媒体文件编码.解码机制,你可以直接调用Android提供的API,实现相册.播放器.录 ...

  9. Java8 新特性简介

    Java8是2014年发布的,至今也已经有快三年的时间了,之前虽然有学习过,但是学的比较零散,不成系统,而且也没有覆盖到Java8所有的特性. 由于公司已经使用了JDK1.8,所以工作中能使用Java ...

  10. 腾讯云数据库团队:MySQL5.7 JSON实现简单介绍

    作者介绍:吴双桥 腾讯云project师 阅读原文.很多其它技术干货.请訪问fromSource=gwzcw.57435.57435.57435">腾云阁. 本文主要介绍在MySQL ...