C++中消息自动派发之三 About JSON Encode

  《C++ 消息自动派发》系列上篇介绍了IDL解析器,生成的C++代码只支持JSON转C++ struct。 经过新的重构,这次增加了对C++ struct 转JSON的支持。IDL解析器自动为C++ struct生成两个方法。

  decode:实现json 转C++ struct 转。

  encode:实现C++ struct 转json字符串。

  现实应用中,网络服务器程序处理流程如下:

  1> 网络层异步接收Client消息(本文讨论的应用都是基于json协议)

  2> 对消息进行解析,如判断消息类型,消息体字段检查、解析、赋值等。将解析完成的结果封装到特定的struct中(每一个消息类型定义单独一个struct)。注:JSON解析、检查、取值都是再网络线程完成(多线程),通常服务器程序的核心逻辑都是在单线程中完成,故逻辑线程应重点”保护“之。待消息转成struct后,逻辑线程直接操作二进制,尽最大程度提高逻辑线程的实时性、吞吐量。

  3> 逻辑线程处理完请求,一般会产生特定的响应结果(有时是一个,如rpc请求,有时多个,如广播消息)。响应结果仍然要同过json协议发送给client。

  4> 逻辑成生成的响应结果为二进制struct,需要转换成json字符串。同样这些耗时的、与逻辑无关的操作应该放到网络线程。道理还是一样,尽最大程度保证

    逻辑层的效率。

  完整示例代码 svn co http://ffown.googlecode.com/svn/trunk/fflib/lib/generator/

1. 用例

  假设一个玩家查询好友信息接口。client发送get_friends_req请求,参数为uid,服务器查询该user的好友,生成好友列表list,返回消息结果。

  首先定义IDL文件,其中有两个消息体:

//! 定义请求消息类型:
struct get_friends_req_t
{
    uint32 uid;
};

//! 定义服务器响应结果消息体类型, ret_t 结尾,代表此消息为响应消息,服务器不需要处理此消息的请求

     对应的服务器实现代码如下所示,稍微做些解释:

  1> socket_t 封装linux socket 文件描述符操作,这里只是个示例,其提供async_write接口,使用preactor模式发送数据。其接受所有消息的基类指针,并且该指针为智能指针,无需手动析构。消息体基类支持encode接口,讲二进制struct转成json字符串,socket则将json字符串通过write系统调用发送给client。

  2> logic_service_t 逻辑层,处理所有的消息请求。针对每一个消息定义重载一个handle函数,为了避免网络层消息传到逻辑层的内存拷贝,这里使用智能指针,同时避免了手动管理。

  3> msg_dispather_t, 这个类是由idl 解析器自动生成的,在生产环境,应该有网络层调用此对象。由于本文只是示例,故忽略网络层,由main模拟网络层调用。

class socket_t
{
public:
    void async_write(msg_ptr_t msg_)
    {
        //! TODO do io write
        cout <<"wile send:" << msg_->encode_json() <<"\n";
    }
};

typedef socket_t* socket_ptr_t;

class logic_service_t
{
public:
    void handle(shared_ptr_t<get_friends_req_t> req_,  socket_ptr_t sock_)
    {
        cout << "req uid:" << req_->uid <<"\n";
        //! DO some logic code
        shared_ptr_t<all_friends_ret_t> msg(new all_friends_ret_t());

        for (int i = 0; i < 10; ++i)
            msg->friends.push_back(i);

        sock_->async_write(msg);
    }
};


int main(int argc, char* argv[])
{
    try
    {
        string tmp = "{\"get_friends_req_t\":{\"uid\":12345}}";
        logic_service_t logic_service;
        msg_dispather_t<logic_service_t, socket_ptr_t> msg_dispather(logic_service);
        //! 这里实际上应该被网络层调用
        socket_ptr_t sock = new socket_t();
        msg_dispather.dispath(tmp, sock);
    }
    catch(exception& e)
    {
        cout <<"e:"<< e.what() <<"\n";
    }
    cout <<"main end ok\n";
}

2. 使用IDL 生成 C++ 代码:

  idl_generator.py  example.idl msg_def.h

  前面定义的example.idl 经过idl_generator.py 分析后生成头文件msg_def.h, 其中包括 msg_dispather_t 的实现,其主要代码为:

struct all_friends_ret_t : public msg_t {
    vector<uint32> friends;
    int parse(const json_value_t& jval_) {

            json_instream_t in("all_friends_ret_t");
            in.decode("friends", jval_["friends"], friends);
        return 0;
    }

    string encode_json() const
    {
        rapidjson::Document::AllocatorType allocator;
        rapidjson::StringBuffer            str_buff;
        json_value_t                       ibj_json(rapidjson::kObjectType);
        json_value_t                       ret_json(rapidjson::kObjectType);

        this->encode_json_val(ibj_json, allocator);
        ret_json.AddMember("all_friends_ret_t", ibj_json, allocator);

        rapidjson::Writer<rapidjson::StringBuffer> writer(str_buff, &allocator);
        ret_json.Accept(writer);
        string output(str_buff.GetString(), str_buff.Size());
        return output;
    }
        
    int encode_json_val(json_value_t& dest, rapidjson::Document::AllocatorType& allocator) const{

        json_outstream_t out(allocator);
        out.encode("friends", dest, friends);
        return 0;
    }

};

3. encode 和 decode 如何实现

  通过不断开发IDL解析器,进一步优化了json的解析和编码。其中:

  1> json_instream.h 完成json的decode,依次遍历struct中的字段,为其赋值。json_instream_t中重载了支持所有类型参数的decode参数。

  2> json_outstream.h 完成struct 转json,依次遍历struct中的字段,将其转为json value,其重载了支持所有基本类型的encode参数。

  示例代码:

    json_outstream_t& encode(const char* filed_name_, json_value_t& jval_, int8_t dest_);
    json_outstream_t& encode(const char* filed_name_, json_value_t& jval_, uint8_t dest_);
    json_outstream_t& encode(const char* filed_name_, json_value_t& jval_, int16_t dest_);
    json_outstream_t& encode(const char* filed_name_, json_value_t& jval_, uint16_t dest_);
    json_outstream_t& encode(const char* filed_name_, json_value_t& jval_, int32_t dest_);
    json_outstream_t& encode(const char* filed_name_, json_value_t& jval_, uint32_t dest_);
    json_outstream_t& encode(const char* filed_name_, json_value_t& jval_, int64_t dest_);
    json_outstream_t& encode(const char* filed_name_, json_value_t& jval_, uint64_t dest_);
    json_outstream_t& encode(const char* filed_name_, json_value_t& jval_, bool dest_);
    json_outstream_t& encode(const char* filed_name_, json_value_t& jval_, float dest_);
    json_outstream_t& encode(const char* filed_name_, json_value_t& jval_, const string& dest_);

 4. TODO 

   1. IDL 解析器已经实现了基本功能,下次准备利用此IDL 解析器实现一个聊天服务器。

   2. IDL 解析器添加对二进制encode/decode的支持。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏夏时

用PHP读写文本文档制作最简单的访问计数器

942
来自专栏更流畅、简洁的软件开发方式

预防SQL注入攻击之我见

1、 SQL注入攻击的本质:让客户端传递过去的字符串变成SQL语句,而且能够被执行。 2、 每个程序员都必须肩负起防止SQL注入攻击的责任。   说起防止SQ...

3576
来自专栏JetpropelledSnake

SQL学习笔记之项目中常用的19条MySQL优化

MySQL对于IN做了相应的优化,即将IN中的常量全部存储在一个数组里面,而且这个数组是排好序的。但是如果数值较多,产生的消耗也是比较大的。再例如:select...

953
来自专栏Ken的杂谈

屏蔽浏览器对网页JS脚本错误提示

网页脚本基本已经成了现在网站开发中不可或缺的元素,无论是使用JS:Javascript还是使用其他JS库:

881
来自专栏程序员叨叨叨

听说你们家的NotifyDataSetChanged不起作用了

前几天,公司项目准备上线,就在前一晚,出现了一个BUG:主页界面刷新无效。千钧一发之际,用了一个笨方法,每次刷新的时候重新setAdapter一下算是实现了基本...

672
来自专栏Golang语言社区

游戏服务器之内存数据库redis客户端应用(上)

本文主要介绍游戏服务器的对redis的应用。介绍下redis c++客户端的一些使用。 存储结构设计: (1)装备道具的redis存储结构为例(Hashes存储...

3808
来自专栏13blog.site

Spring+SpringMVC+MyBatis+easyUI整合基础篇(八)mysql中文查询bug修复

前言   在测试搜索时出现的问题,mysql通过中文查询条件搜索不出数据,但是英文和数字可以搜索到记录,中文无返回记录。本文就是写一下发现问题的过程及解决方法...

2875
来自专栏cloudskyme

jbpm5.1介绍(2)

快速开始  首先下载jBPM,http://sourceforge.net/projects/jbpm/files/ 可以有选择性的下载: bin:jBPM的二...

3376
来自专栏张善友的专栏

VS 2005 文本编码小技巧

     VS2003使用代码生成器生成的代码加入到工程会很郁闷的,在智能提示中是乱码,在VS2005中有一个选项可以解决这个问题。      今天将一个工程从...

1826
来自专栏林冠宏的技术文章

浅谈 maxMemory , totalMemory , freeMemory 和 OOM 与 native Heap

作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:htt...

33413

扫码关注云+社区