分类目录归档:社区开源项目

iguana支持了C++17

iguana做了更新,增加了C++17的版本,之前C++14的版本并不受影响。

如何使用

如何使用C++17版本的iguana呢?很简单。

  1. 需要支持C++17的编译器:gcc7.1, clang4.0,由于vs2017只支持了很少的C++17特性,因此在vs2017上用不了C++17版本的iguana.

  2. 引用C++17版本的头文件,如include “json17.hpp”即可。

  3. CMakelists.txt中设置C++17的flag。

用到了哪些C++17的新特性?

主要用到了C++17的constexpr:constexpr if, constexpr lambda; fold expression, string_view, inline variable, nested namespace.

C++17用起来很舒服,enjoy it.

欢迎大家使用基于编译期反射的序列化引擎iguana

扩展模板库的新方法 – 善用函数的ADL查找

问题

随着C++语言的发展,越来越多的C++类库都使用模板库提供给大家使用。模板库通常使用基于对象的设计,相比传统的面向对象的设计而言,前者的每个模块可以单独使用,而不依赖框架。整个模板库的框架,只是一个胶水层,让各个组件之间按照某种协议,组合到一起,形散而神不散,发挥出强大的功能。而且模板库非常好扩展。模板库的扩展通常有以下三种模式:

  1. 函数重载;
  2. Policy Based Design, 按照框架规定好的协议导出指定的type,计算好特定的静态常量和实现特定的函数;
  3. 特化traits或者一些特定模板组件的特化;

由于前两种方式比较简单,还要就是没有找到比较好的素材,鄙文暂时主要讨论第三种扩展方式。在实现iguana的过程中,我们发现模板特化和宏的结合,在碰到命名空间的时候,我们一筹莫展。案例如下,

REFELCTION宏实质上生成了一个在全局命名空间下的类模板的特化的代码。但是由于宏是预处理阶段,生成的代码在client命名空间下。C++的语言规范不允许在一个命名空间中特化另一个命名空间的类模板,也不允许在一个命名空间下特化全局命名空间的类模板(全局的情况MSVC能编过,我是服气的)。这里是一个参考链接。

那么我们库中遇到的问题,用下列简化的代码给出,有兴趣的读者可以到各个编译环境下测试。

其实这个限制并不是无解,只要你保证REFLEACTION宏在全局命名空间下,就不会出错。例如BOOST_FUSION_ADAPT_STRUCT宏,也是用相同的方法规避的。但是你会发现这样对使用来说非常不便,你偶尔不得不把一个完整的命名空间的代码block拆成两个。我们得找另外一种方法来扩展我们的模板库,而不受限于命名空间。

解决方案

什么样的扩展方法,可以跨越命名空间的限制?仔细阅读过template C++的读者应该不难发现,就是函数的ADL查找。我们用如下代码来说明,如何利用函数的ADL查找。

简单解释一下,下面的代码是如何工作的。首先,函数的ADL查找,是apply函数尝试调用to_extend的时候,不仅会查找lib命名空间下的符号,也会去查找T类型所在命名空间的符号。我们定义的to_extend函数在client命名空间下,foo类型也在client命名空间下。那么ADL查找肯定可以找到to_extend函数的符号。然后,我们没有选择类模板的特化,而是选择了使用to_extend函数,返回一个它内部定义的类型作为policy的功能。这个思想有点类似Andrei Alexandrescu大神的MDC中第11章节的Multimethod的蹦床函数,trampoline funciton. 有了这些,我们就可以在任意命名空间下来扩展我们的模板库,当然配合宏使用也没有问题了。在iguana中具体实现的小细节,可以参考reflection.hpp里面的实现。

A Universal ORM Engine based on compile time Reflection

A Universal ORM Engine based on Reflection

ormpp is a modern, universal and easy-to-use ORM engine developed in c++14. ormpp only supports sqlite now, however ormpp can support any database, such as mysql, postgresql,oracle etc. ormpp will support many kind of database in future. ormpp is in developing now.

Motivation

Simplify database operation with compile-time reflection.ormpp provides very simple and universal interface, although the databases type are different.In short ormpp shields the difference of the bottom database.
This library provides a portable cross-platform way of:

  • operation of sqlite
  • operation of mysql(in the paln)
  • operation of postgresql(in the paln)
  • operation of any other database

Tutorial

This Tutorial is provided to give you a view of how to use ormpp, now it is only concerned with sqlite.

Data manipulation

Create a database.

Create a table.

The excecute method is a universal interface, it can accept any data manipulation sql string. So you can also call excecute for insert, update and delete etc.

Binding parameters.

The excecute interface support binding parameters, bellow is an example.

If the statement needs some later binding parameters, pass the parameters straight forward. ormpp will atomically binding theparameters.

Operation with object

If you get tired of filling many parameters, you can choose object instead. ormpp can automatically make sql with compile-time reflection.Bellow is an example of inserting with object.
Firstly, define meta data just as iguana dose.

Secondly, directly call excecute interface.

ignore some fields of an object

insert interface provides a default parameter which is used to tell ormpp which fields would be ignored.Just need pass the fields indexes.Bellow is an example about ignore specific fields:

Query table

Query table is also very simple, just need call a query interface with a reflection object.

How about multiple tables query? Still call the query interface.

If you query parts of tables, still call the query interface

Full sources:

  • https://github.com/qicosmos/ormpp/blob/master/example.cpp

If you found a bug, please create an issue on GitHub with a detailed description. If you like it please star it

A universal serialization engine based on compile time reflection

iguana is a modern, universal and easy to use serialization engine developed in c++14.

Motivation

Serialize an object to any other format data with compile time reflection, such as json, xml, binary,table and so on.
This library was degined to unify and simplify serialization in a portable cross-plateform manner. This library is also easily to extend, you can serialize any format data with the library.
Library provides a portable across platforms way to:

  • serialization of json
  • serialization of xml
  • serialization of any customized format

Tutorial

This Tutorial is provided to give you an view of how to iguana for serialization.

serialization of json

The first thing to do when you serialize an object is to define meta data. There is an example of defining meta data.

Defining meta data is very simple, just needs to difine a ‘REFLECTION’ micro.

Now let’s serialize person to json string.

This example will output:

serialize person to json string is also very simple, just need to call to_json method, there is nothing more.

How about deserialization of json? Look at the follow example.

It’s as simple as serialization, just need to call from_json method.

serialization of xml

Serialization of xml is similar with json. The first step is also defining meta data as above. This is a complete example.

a complicated example

iguana can deal with objects which contain another objects and containers. Here is the example:

At first define meta data:

Then call the simple interface:

Full sources:

  • https://github.com/qicosmos/iguana/blob/master/example.cpp

F.A.Q

  • Question: Why is the name called iguana?

    • Answer: I think serialization is like an iguana, because the change is only the display format, however the meta data is never changed. With changeless meta data and reflection you can serializa an object to any format which is like an iguana does.
  • Question: Is iguana support raw pointer?

    • Answer: No. iguana doesn’t support raw pointer, but will surpport smart pointer in the future.
  • Question: Is iguana thread safe?

    • Answer: Not yet, but it’s not a problem, you can use lock before call from_json or to_json.
  • Question: Is iguana high performance?

    • Answer: Yes it is, because iguana is based on compile time reflection.
  • Question: I have found a bug, how do I notify?
    Answer: Create an issue at GitHub with a detailed description.

If you like iguana, please star it, thanks.

rest_rpc v0.91 release

新增特性

1.业务函数的参数可以有connection_ptr,也可以没有,取决于你的需要,使用更灵活。

2.客户端添加private接口,拥有更高的权限和更多的流程控制

3.server端的pub提供了一个纯转发的重载实现

4.提供管理多个endpoint的工具

5.客户端pub接口的,将会把转发协议的name当做topic,广播给所有监听这个topic的客户端,而不需要再服务器上注册handler;

6.服务器注册handler,将使用hash值代替字符串

Bug修复

1.rpc超时后异步调用链断开

2.客户端和服务器read大块消息时,因使用boost::bind,而发生了意外地拷贝,招致读取到不正确的地址

3.支持更低版本的编译器

详细可以看这里。

真正好用的RPC框架rest_rpc正式发布第一个版本

rest_rpc是由c++开源技术社区(purecpp.org)创建和发起的项目,在经过多次迭代和重构之后,终于发布第一个版本了。rest_rpc是modern c++开发的一个易用、灵活、跨平台和高性能的RPC框架。和国内外一些大公司开发的RPC框架相比,rest_rpc有哪些特色呢?

rest_rpc的特点

rest_rpc具备下面几个特点

  • 真的像本地函数一样调用
  • 使用简单,用户只需要关注业务即可
  • 灵活,RPC调用的序列化方式可以自由定制,比如支持json,支持msgpack等方式
  • 支持同步和异步调用

这几个特点也是之前的文章里提到的评价一个RPC是否好用的标准,无疑rest_rpc完全符合这些标准,是一个真正好用的RPC,并且还走得更远。

传统的网络库处理业务逻辑的过程一般分为5步:

  1. 接收网络数据;
  2. 解析网络数据;
  3. 调用业务逻辑;
  4. 打包结果;
  5. 发送数据;

如果使用rest_rpc,就只有1步了

1.只需要调用业务逻辑(其他的框架都帮你做好了)。

rest_rpc提供一站式服务,将1,2,4,5步完全省略掉,让用户只用关注第3步的业务逻辑即可,省心省力!如果用户之前用到了其他的网络库,想换成rest_rpc也很简单,不需要做任何修改,只要把业务逻辑函数注册一下就行了,可以直接复用,什么都不用改,省心省力!

rest_rpc的最主要的特点是好用,用户只需要像本地调用那样去调用RPC服务接口,无需关注框架和网络的细节既可以实现远程调用,只需要关注自己的业务逻辑即可。除了易用的特点之外,rest_rpc还具备很好的灵活性,用户可以选择RPC序列化的方式,还支持自定义的序列化方式。

rest_rpc的使用

我们以一个最简单的例子来展示如何使用rest_rpc,这个例子中,服务器提供了一个 int add(int a, int b) RPC服务接口,客户端通过RPC调用获取远程调用的结果。

  • 服务器端代码

  • 同步客户端代码

至此,一个RPC程序就完成了,无论是服务器还是客户端,代码都非常少,总共都不到10行代码,用户只需要关注业务逻辑即可,无需关注网络或者框架细节,而且和调用本地函数一样,非常好用,没有任何限制。

  • 异步客户端代码

一个更复杂的例子

这个例子将展示RPC接口中含有二进制数据的情况,有些RPC框架如果要支持二进制的话,需要将二进制做一些转换,比如base64转换之类的,rest_rpc支持原始的二进制数据,无需做任何转换。

  • 服务器端代码

  • 客户端代码

使用方式还是那么简单,自然,因为rest_rpc框架已经帮你做了绝大部分事情了。

rest_rpc编译

rest_rpc是由c++14编写的,因此需要支持C++14的编译器,windwos上需要vs2015, linux需要gcc5.0+, 除此之外还用到了boost,因此还需要boost库。

RPC调用需要注意的地方

需要注意的地方主要是就是客户端需要做异常处理,因为RPC调用可能会失败,出错的原因比较多,可能是客户端和服务器的连接断开了,也可能是服务器没有提供这个RPC服务,也可能是服务器提供的RPC服务发生了异常。总之,rest_rpc框架会将错误码和出错信息作为异常抛出来。所以更完整的做法是在call之外捕获一下异常,做异常处理。

此外,服务器在默认情况下是在io线程中执行业务函数的,如果用户需要执行一个非常耗时的操作,rest_rpc提供了一个异步执行业务函数的接口。

异步客户端

同步客户端会阻塞调用call的线程,虽然简化了逻辑但是也降低了性能。rest_rpc也实现了异步客户端,接口也很好用。

  • 异步客户端示例

  • 异步客户端同步接口
    异步客户端除了纯异步以外,还有同步接口,可以让用户选择在何时阻塞。

性能测试

rest_rpc的性能很高,下面是用异步客户端对add RPC服务接口做的性能测试结果,因为RPC是请求-响应模式,所以实际上做的是含有业务逻辑的pingpang测试,包括数据解包、业务执行、结果打包发送的过程。

上面是在一台12核(主频2.4G)24线程的服务器上测试的,qps为46万时,cpu占用63%左右。

代码质量

下面是用工具检测的代码质量图

代码的可读性较好。

如果你仅仅需要RPC的话,看到这里就可以不用往下看了

如果你还有更多期待,请往下看。

还有点其他的什么吗?

是的,还有一些特别的东西,rest_rpc不是仅仅提供了一个RPC功能而已,还提供了更有趣的功能,比如订阅-发布!是的,你没看错,rest_rpc具备pub/sub功能,也许有人会觉得奇怪,为什么RPC框架会提供订阅-发布功能呢。其实,RPC和订阅-发布是有相通的地方。RPC可以看作是一个特殊的订阅-发布模式,即订阅者和发布者都是自己,而订阅-发布模式又可以看作是一个特殊的扩展了的RPC,即发起RPC调用的人和接收RPC调用结果的人是不同的人。正是看到了这种相通性,rest_rpc顺手就实现了订阅-发布模式。订阅-发布模式用起来也很简单,和RPC调用差不多,下面来看一个订阅发布的例子。

  • 服务器端代码

  • pub客户端代码

鉴于pub和sub天然的异步属性,我们只在异步客户端实现了这个接口,同步客户端暂不支持

  • sub客户端代码

订阅发布还是那么简单。rest_rpc相比其他的RPC框架,不仅仅提供了更加易用、灵活的RPC接口,还提供了额外的订阅发布功能,而且订阅-发布可以和RPC调用随时结合起来使用,使得RPC和订阅-发布的功能更加强大。

Kapok发布1.0版本了

kapok1.0发布了

kapok的特点

kapok是一个高性能跨平台的对象-json序列化的库,对象序列化后是标准的json格式,json格式的字符串可以直接反序列化为对象。简单,易用,header-only,只需要引用Kapok.hpp即可。它由c++14实现,因此需要支持C++14的编译器。

kapok除了支持结构体、容器和数组之外,还支持boost.optional和boost.variant,使用起来非常方便。

性能对比

kapok序列化和反序列化的性能很高,综合性能比msgpack要高,下面是性能对比的代码

综合测试

测试msgpack

测试kapok

测试结果

单项测试

分别测试msgpack序列化和反序列化的耗时

分别测试kapok的序列化和反序列化的耗时

测试结果

测试结论

从单项测试结果看,msgpack的序列化比kapok快大约2-3倍,而kapok的反序列化速度比msgpack快了5倍,综合性能,kapok比msgpack快4-5倍。

使用示例

  • 普通对象

  • 枚举对象

  • std::pair

  • std::array

  • std::tuple

  • boost.optional

  • boost.variant

  • 嵌套的容器和对象

需要注意的地方

  • kapok不支持指针,当序列化的对象中含有指针的时候会出现编译错误。

  • 反序列化的时候,如果反序列化和序列化的字段类型不匹配的时候,kapok会忽略该字段,不会赋值。

  • 序列化/反序列化过程中kapok可能会抛出异常,用户需要在外面捕捉异常。

  • kapok不是线程安全的,如果需要多线程操作的话,请用户在外面自行加锁。

  • 序列化的对象一定要定义META宏,否则会出现编译错误。

rest_rpc的三种工作模式

rest_rpc的三种工作模式

rest_rpc的使用非常灵活,支持三种工作模式:请求-应答模式、stream流模式和订阅发布模式,下面来分别介绍这三种工作模式。

三种工作模式

  • 请求-应答模式

    这种模式就是使用RPC的经典模式,用起来也最简单,客户端发送调用请求,服务器返回调用结果。请求和结果都是json格式。

  • stream流模式

    流模式就是传统的tcp/ip流的发送方式,客户端发送原始的二进制流数据到服务器,服务器根据约定的协议处理数据。流模式下,服务器不会返回响应给客户端。一般情况下,流模式和请求应答模式结合起来使用会更方便。

  • 订阅发布模式

    订阅发布模式可以看成是前两种模式的一种扩展,订阅者接受某个主题的结果,发布者触发某一个主题的调用,调用的结果会发送到所有订阅了该主题的订阅者。请求-应答模式可以看作是一种特殊的订阅-发布模式,即订阅者和发布者都是自己。

    订阅发布模式要分为订阅和发布两种使用情况,订阅主题的时候通过请求应答模式是非常方便的,在发布主题的时候可以使用请求应答模式也可以使用stream流模式,发布的时候可以要求服务器返回调用结果,也可以不需要返回结果。

    订阅者候始终是被动接收服务器广播的结果,仅仅在被动接收数据之前允许使用请求-应答模式告诉服务器订阅了什么主题。

    需要注意的是,请求-应答和stream模式可以在一个client里使用,而订阅发布需要一个单独的client。

三种工作模式的使用

  • 请求应答模式

    请求应答模式下仅仅需要调用通用接口call接口即可,使用示例

  • stream流模式

    stream流模式仅仅需要调用call_binary接口即可

  • 订阅发布模式

    服务器

    订阅客户端

    发布客户端

rest_rpc使用示例 — 文件上传

rest_rpc使用示例

rest_rpc即支持请求-应答模式,也支持no-response模式,用户可以随意选择这两种模式。rest_rpc支持json格式数据的传输,还支持无性能损耗的原始二进制流的传输(无需通过base64或者16进制转码),用户可以随意选择自己需要的传输格式。
下面是一个客户端向服务器传送文件的例子,这个例子中展示了如何选择应答和非应答模式,以及用json传输和二进制传输,非常灵活地完成传文件的功能。

服务器端的代码:

  • 先创建一个文件传输的类

这个类定义了4个服务函数,这4个函数是直接暴漏给客户端的,可以看到,其中upload函数是直接接受二进制流数据,它没有返回值,所以它不会向客户端返回响应,其他的函数则会向客户端返回一个response来表明服务器端的调用是否成功。
这几个函数通过字面意思就可以清晰地知道含义,文件传输流程是这样的,客户端先告诉服务器希望保存的文件名,服务器应答成功之后,客户端就开始分段发文件的二进制流数据给服务器了,当文件传输完之后,再通知服务器文件传输完成,服务器保存文件,至此,整个文件传输的过程结束了。

  • 发布服务接口

业务类定义完成之后,接下来就是暴露服务接口给客户端了,让客户端可以像调用本地函数一样很方便地使用,而这对于rest_rpc来说是非常简单的事。

这样我就对外提供了4个服务接口,接下来看看客户端是如何调用这几个服务接口实现文件上传的。

客户端的代码

总结

可以看到rest_rpc使用起来非常灵活,也非常简单,后续还会继续增加一些rest_rpc的使用示例。完整的代码可以在rest_rpc的exapmle中看到。

Copy Protected by Chetan's WP-Copyprotect.