不同进程间通信都需要一些标识来定义本次通讯的意义及数据格式,而这些标识常常被称为消息,接下来讨论如何组织这些标识及与之对应的数据格式。
     传统的是的使用常量(枚举或宏)来定义消息编号,使用结构体来定义各消息的数据格式。在解析时switch-case常量来使用相应的结构体解析数据并进行处理,这种原生的方式会带来各种问题:使switch-case处理函数会变得相当长导而致难以维护;消息编号和其数据格式结构体映射混乱;不利于新增消息的分流等等。而后又演变出分段、消息结构体继承等思想以缓解这种情况。今天我探寻的是延续这些思想并进行扩展,使消息的定义、使用更方便。
      在解决"大"问题的时候,使用分治法往往都能收到很不错的效果,面对数以千记的消息,果断地将它们分段,分段上再应用点小策略:从逻辑上来看各分段形成一颗树形结构,该树的每个节点要么是具体的消息,要么是一个分段。每个节点都有一个值和类型(核心思想),其中节点值在兄弟间唯一的,节点类型是继承自父节点的类型。仅有分段才能具有子节点。如图:
                    _root_
                   /              \
               protocola     _segmentA_
                                 /           |          \
           _segmentAA_  _segmentBB_  protocolaa
                  ...          ...
            [root为消息的根节点,segment为消息段,protocol为消息编号]

消息值和消息类型都在其父节点的域内,如访问消息protocola为_root_::protocola。这样做主要是防止命名冲突,如组队系统中有同意邀请消息,而副本系统也有同意邀请消息。

Ok,话了这么多,直接上码:

/

typedef unsigned char PROT_TYPE;            // 消息编号类型

// 根消息段。
namespace msg_ROOT_sg
{
    struct ROOT_dt   { PROT_TYPE No() { return _no; } protected: PROT_TYPE _no; };
    typedef ROOT_dt MyDT;
}

// 开始定义一个段
// belong所属段名 segment当前段名
#define BEGIN_DEFINE_SEGMENT(belong , segment)                      \
            namespace msg_##segment##_sg                            \
            {                                                       \
                typedef msg_##belong##_sg::segment##_dt MyDT;

// 结束定义一个段
#define END_DEFINE_SEGMENT(segment)    }

// 在段的定义中声明一个段
// segment段名 value段的值(该值必须是父亲直接孩子中唯一的)
#define DECLEAR_SEGMENT(segment , value)                            \
            static PROT_TYPE const segment = value ;                \
            struct segment##_dt: public MyDT                        \
            {                                                       \
                segment##_dt() { MyDT::_no = segment; }             \
                PROT_TYPE No ()     { return _no ; }                \
                protected: PROT_TYPE _no;                           \
            };

// 在段的定义中声明一个消息
// protocol消息名 value消息的值(该值必须是父亲直接孩子中唯一的)
#define DECLEAR_PROTOCOL(protocol , value)  static PROT_TYPE const protocol = value;

// 段的定义外开始定义一个消息
// belong所属段 protocol消息名
#define BEGIN_DEFINE_PROTOCOL(belong , protocol)                    \
            namespace msg_##belong##_sg                             \
            {                                                       \
                struct protocol##_dt : public MyDT                  \
                {                                                   \
                    protocol##_dt() { MyDT::_no = protocol; }

// 段的定义外结束定义一个消息
// protocol消息名
#define END_DEFINE_PROTOCOL(protocol )   }; }

// 在段的定义中定义一个消息
// protocol消息名 value消息的值(该值必须是父亲直接孩子中唯一的)
#define DEFINE_PROTOCOL(protocol , value)                           \
            static PROT_TYPE const protocol = value ;               \
            struct protocol##_dt : public MyDT                      \
            { protocol##_dt() { MyDT::_no = protocol; } };

BEGIN_DEFINE_SEGMENT(ROOT, ROOT)             // 根节点的所属段依旧是根。而且段名必须是ROOT
    DECLEAR_SEGMENT(CHAT, 1)                 // 声明聊天段
    DEFINE_PROTOCOL(GC_HEART_DETECT, 100)    // 定义GC_HEART_DETECT消息,该消息不附带额外的数据。
END_DEFINE_SEGMENT(ROOT)

// 定义聊天消息段
BEGIN_DEFINE_SEGMENT(ROOT, CHAT)
    DECLEAR_PROTOCOL(CS_GMCHAT, 10)         // 声明GM聊天消息
END_DEFINE_SEGMENT(CHAT)

// 定义GM聊天消息
BEGIN_DEFINE_PROTOCOL(CHAT, CS_GMCHAT)
    char            szContext[128];             // 内容
    unsigned char   byType;                     // 类型
END_DEFINE_PROTOCOL(CS_GMCHAT)

/

#include <iostream>

#include<windows.h>

void Recv(msg_ROOT_sg::ROOT_dt *pData);             // 模拟全局消息处理函数
void MsgProc_Chat(msg_ROOT_sg::CHAT_dt *pData);     // 处理聊天系统的消息函数(模拟具体的消息段)

int _tmain(int argc, _TCHAR* argv[])
{
    msg_CHAT_sg::CS_GMCHAT_dt data;
    strcpy(data.szContext, "this a test");
    data.byType = 100;
    void *pData = &data;                                                            // 模拟网络传输后
    Recv((msg_ROOT_sg::ROOT_dt *)pData);

msg_ROOT_sg::GC_HEART_DETECT_dt detect;
    pData = &detect;                                                            // 模拟网络传输后
    Recv((msg_ROOT_sg::ROOT_dt *)pData);

system("pause");
    return 0;
}

void Recv(msg_ROOT_sg::ROOT_dt *pData)
{
    switch (pData->No())
    {
    case msg_ROOT_sg::CHAT:
        MsgProc_Chat((msg_ROOT_sg::CHAT_dt*)pData);
        break;
    case msg_ROOT_sg::GC_HEART_DETECT:
        std::cout << "Msg: GC_HEART_DETECT" << std::endl;
        break;
    default:break;
    }
}

// 处理聊天系统的消息函数
void MsgProc_Chat(msg_ROOT_sg::CHAT_dt *pData)
{
    switch (pData->No())
    {
    case msg_CHAT_sg::CS_GMCHAT:
        {
            msg_CHAT_sg::CS_GMCHAT_dt *pChat = (msg_CHAT_sg::CS_GMCHAT_dt*)pData;
            std::cout << "Msg:CS_GMCHAT  ";
            std::cout << "Chat:" << pChat->szContext << " Type:" << pChat->byType << std::endl;
        }
        break;
    }
}

PS: 几个项目一步一步总结出来的,现也运用在项目中~但未必完美,望不吝赐教!

排版貌似乱了,我是直接从偶的demo中拷贝出来的,懒得排了....感兴趣自己拷到.h/.cpp中去看。

网络游戏中通信消息的组织相关推荐

  1. DELPHI 中 Window 消息大全使用详解

    Window 消息大全使用详解 导读: Delphi是Borland公司的一种面向对象的可视化软件开发工具. Delphi集中了Visual C++和Visual Basic两者的优点:容易上手.功能 ...

  2. 深度解析VC中的消息(上)

    消息是指什么?      消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉.一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向Windows发出一个通知,告诉应用程 ...

  3. 如何在优雅地Spring 中实现消息的发送和消费

    本文将对rocktmq-spring-boot的设计实现做一个简单的介绍,读者可以通过本文了解将RocketMQ Client端集成为spring-boot-starter框架的开发细节,然后通过一个 ...

  4. OSSIM中分布式消息队列应用

     OSSIM中分布式消息队列应用 1. 消息队列处理 企业日志数量正在以指数级形式高速增长,日志数据的具有海量.多样.异构等特点,基于传统的单一节点混合式安装的OSSIM平台(指OSSIM 4.4及以 ...

  5. JMS中的消息通信模型

    1. MQ简介: 消息队列(Message Queue,简称MQ),是应用程序与应用程序之间的一种通信方法.应用程序通过发送和检索出入列队的针对应用程序的数据 - 消息来通信,而无需专用连接来链接它们 ...

  6. 如何在优雅地Spring 中实现消息的发送和消费 1

    本文将对rocktmq-spring-boot的设计实现做一个简单的介绍,读者可以通过本文了解将RocketMQ Client端集成为spring-boot-starter框架的开发细节,然后通过一个 ...

  7. 网络游戏中网络模块浅析

    在网络游戏中,不论是服务端还是客户端都需要网络通讯的功能模块,而一个优秀的成熟的网络通讯模块,又可以用于多个游戏产品中. 于是,在学习的过程中,设计和实现一个可复用的网络通讯模块,变得非常的有意义. ...

  8. java中的消息队列

    消息队列:可以看做是一个存储消息的容器,它是分布式系统中的重要组件之一. 目的是: 1.为了通过异步处理来提高系统的性能来减少系统响应的时间 一般的步骤是客户端发起请求给服务端,服务端在请求给数据库, ...

  9. Android中的消息推送

    转载于Android中的消息推送 前段时间做了一个应用,需要用到服务器端向Android或者是Iphone终端主动发送命令.随后客户端做出相应的反应.当时没有找到最佳的方案,一直搁置着.今天看到网上有 ...

最新文章

  1. 用UltraIso刻录XP到U盘安装是不行的
  2. 你知道Linux里D进程会搞事吗?
  3. 二叉树介绍与代码实现
  4. python基础--局部变量与全局变量
  5. Blockchain.com,Eden Block,DACM等知名公司加入Pocket生态
  6. Cocosd-x”设计模式“之五 :防御式编程”模式“
  7. 用安卓软件MT管理器破解元气骑士内购,小白照着也可以成功!
  8. which在C语言用法,A,B, and C, which ... which指代的是它们三个还是只有C呢?
  9. 区分统一社会信用代码、组织机构代码、注册号
  10. 这可能是全网最全的车载OS整理
  11. 2020年12月电子学会Python等级考试试卷(一级)考题解析
  12. Android相关简述题
  13. java poi row cell,使用POI进行Excel操作的总结一——创建Workbook,Sheet,Row以及Cell
  14. 如何把两段即以上视频合并成一个
  15. JSX介绍-基本使用
  16. 【nmon】nmon :服务器性能结果报告分析 —— 报表参数详解
  17. 马云再次成功了!刚刚,阿里巴巴正式宣布再出两大产品!
  18. tradingView--K线图 使用
  19. AmbiguityVis: Visualization of Ambiguity in Graph Layouts
  20. 马云告诉你在农村做什么赚钱

热门文章

  1. 无法找到将您的计算机恢复至原始状态,如何解决电脑未找到操作系统的问题
  2. 小窗终曲对中国游戏产业策划的小评(转)
  3. blob没权限 ie_IE浏览器对象不支持Blob属性或方法,IE浏览器不支持canvas toBlob()方法的Polyfill...
  4. MarkDown语法学习--代码区块,链接
  5. 【STM32H7】第22章 ThreadX GUIX窗口图标滑动操作实现方法
  6. android的模拟器打不开了,解决Android模拟器打不开的问题!...
  7. 【51CTO学院三周年】我在学院不得不说的收获
  8. 为IT程序员量身定制的12个目标
  9. Bad Header Pool 0x00000019
  10. dedecms标签大全(都是整理后的经典)