- Notifications
You must be signed in to change notification settings - Fork397
modern C++(C++20), simple, easy to use rpc framework
License
qicosmos/rest_rpc
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
| OS (Compiler Version) | Status |
|---|---|
| Ubuntu 22.04 (clang 14.0.0) | |
| Ubuntu 22.04 (gcc 11.2.0) | |
| macOS Monterey 12 (AppleClang 14.0.0.14000029) | |
| Windows Server 2022 (MSVC 19.33.31630.0) |
c++20, high performance, cross platform, easy to use rpc framework.
It's so easy to love RPC.
Modern C++开发的RPC库就是这么简单好用!
rest_rpc是一个高性能、易用、跨平台、header only的基于c++20 协程的rpc 库,它的目标是让tcp通信变得非常简单易用,即使不懂网络通信的人也可以直接使用它。它依赖header-only的standaloneasio(tag:asio-1-36-0)
可以快速上手,使用者只需要关注自己的业务逻辑即可。
需要完全支持c++20 的编译器:
gcc12+, clang15+, msvc2022
- 博世汽车
rest_rpc为用户提供了非常简单易用的接口,几行代码就可以实现rpc通信了,来看第一个例子
//服务端注册加法rpc服务intadd(rpc_conn conn,int a,int b) {return a + b; }intmain(){ rpc_serverserver("127.0.0.1:9004",std::thread::hardware_concurrency()); server.register_handler<add>(); server.start();}
//客户端调用加法的rpc服务intmain(){auto rpc_call = []() -> asio::awaitable<void> { rpc_client client;auto ec =co_await client.connect("127.0.0.1:9004");if(ec) { REST_LOG_ERROR << ec.message();co_return; }auto r =co_await client.call<add>(1,2);if(r.ec == rpc_errc::ok) { REST_LOG_INFO <<"call result:" << r.value;assert(r.value ==3); } };sync_wait(rpc_call());}
//1.先定义person对象structperson {int id; std::string name;int age;};//2.提供rpc服务personget_person(person p) { p.name ="jack";return p;}intmain(){ rpc_serverserver("127.0.0.1:9004",std::thread::hardware_concurrency()); server.register_handler<get_person>(); server.start();}
//客户端调用获取person对象的rpc服务intmain(){auto rpc_call = []() -> asio::awaitable<void> { rpc_client client;auto ec =co_await client.connect("127.0.0.1:9004");if(ec) { REST_LOG_ERROR << ec.message();co_return; } person p{1,"tom",20};auto r =co_await client.call<get_person>(p);if(r.ec==rpc_errc::ok) { REST_LOG_INFO <<"call result:" << r.value.name;assert(r.value.name =="jack"); } };sync_wait(rpc_call());}
rest_rpc 比较有特色的一个功能是支持订阅发布。
以订阅某个topic为例:
server 端代码:
voidpublish() { rpc_serverserver("127.0.0.1:9004",4); server.async_start(); REST_LOG_INFO <<"will pubish, waiting for input";auto pub = [&]() -> asio::awaitable<void> { std::string str;while (true) { std::cin >> str;if(str =="quit") {break; }// 向客户端发布一个string,你也可以发布一个对象,内部会自动序列化co_await server.publish("topic1", str); } };sync_wait(pub());}client 端代码:```cppvoidsubscribe() { REST_LOG_INFO <<"will subscribe, waiting for publish";auto sub = [&]() -> asio::awaitable<void> { rpc_client client;co_await client.connect("127.0.0.1:9004");while (true) {// 订阅topic1,库会自动将结果反序列化为std::string, 如果publish是一个person对象,则subscribe参数填person,内部会自动反序列化auto [ec, result] =co_await client.subscribe<std::string>("topic1");if (ec != rpc_errc::ok) { REST_LOG_ERROR <<"subscribe failed:" <<make_error_code(ec).message();break; } REST_LOG_INFO << result; } };sync_wait(sub());}
rest_rpc是目前最快的rpc库,具体和grpc和brpc做了性能对比测试,rest_rpc性能是最高的,远超grpc。
性能测试代码在这里:
https://github.com/qicosmos/rest_rpc/tree/master/tests/bench.cpp
rest_rpc 也是比较灵活的,允许用户替换默认的序列化库。
rest_rpc 默认使用yalantinglibs的struct_pack 去做系列化/反序列化的,它的性能非常好。
rest_rpc 也支持用户使用自己的序列化库,只需要去实现一个序列化和一个反序列化函数。
namespaceuser_codec {// adl lookup in user_codec namespacetemplate<typename... Args> std::stringserialize(rest_adl_tag, Args &&...args) { msgpack::sbufferbuffer(2 *1024);ifconstexpr (sizeof...(Args) >1) {msgpack::pack(buffer,std::forward_as_tuple(std::forward<Args>(args)...)); }else {msgpack::pack(buffer, std::forward<Args>(args)...); }returnstd::string(buffer.data(), buffer.size()); }template<typename T> Tdeserialize(rest_adl_tag, std::string_view data) {try {static msgpack::unpacked msg;msgpack::unpack(msg, data.data(), data.size());return msg.get().as<T>(); }catch (...) {return T{}; } } }// namespace user_codec
实现这两个函数之后rest_rpc 将会使用自定义的序列化/反序列化函数了。
rest_rpc 支持零拷贝发数据,以echo函数为例:
std::string_viewecho(std::string_view str) {return str;}
假如用户希望发送很大的一个数据,可能有数GB,如果按照常规的做法,需要先序列化,这样就存在内存拷贝,rest_rpc 针对这种场景专门做了优化,当client调用rpc函数时传入的是std::string_view 时,rest_rpc 将不会对传入的数据做拷贝,也不会去做序列化,直接通过socket发送到服务端。
rpc函数的返回类型为std::string_view 时,client收到的响应数据也不会做反序列化和内存拷贝,直接返回的是收到的socket 数据。
这样就可以实现rpc的零拷贝数据发送了,能获得最佳的性能。事实上当用户的rpc函数的参数为单参数并且类型为基本类型(字符串和数字类型)时,rest_rpc 不会做序列化,以获得更好的性能,只有多参数或者结构体时才会去序列化。
更多例子可以参考rest_rpc的example:
https://github.com/qicosmos/rest_rpc/tree/master/examples
qq群:546487929
About
modern C++(C++20), simple, easy to use rpc framework
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors9
Uh oh!
There was an error while loading.Please reload this page.