2510C++,rest_rpc

原文

这次升级改动主要有以下几个方面:

1,去掉回调全部换成C++20``协程;

2,基于协程订阅发布.

3,序化库换成性能更好的yalantinglibsstruct_pack

4,更安全的编译期检查.

5,提升性能

6,支持用户自定义序化

现在来看看最新的rest_rpc的基本用法:

基本用法

cpp 复制代码
    //定义rpc函数
int add(rpc_conn conn, int a, int b) { return a + b; }
std::string_view echo(std::string_view str) { return str; }
int main(){
  rpc_server server("127.0.0.1:9004", std::thread::hardware_concurrency());
  server.register_handler<add>();
  server.register_handler<echo>();
  server.start();
}

int main(){
  auto rpc_call = []() -> asio::awaitable<void> {
    rpc_client client;
    co_await client.connect("127.0.0.1:9004");
    auto r = co_await client.call<add>(1, 2);
    assert(r.value == 3);
    auto r1 = co_await client.call<echo>("test");
    assert(r.value == "test");
  };
  sync_wait(rpc_call());
}

最简单rpc服务几行代码就行了.rpc函数也可按协程函数定义.

cpp 复制代码
asio::awaitable<std::string_view> echo_coro(std::string_view str) {
  co_return str;
}

int main(){
  rpc_server server("127.0.0.1:9004", std::thread::hardware_concurrency());
  server.register_handler<echo_coro>();
  server.async_start();
  auto rpc_call = []() -> asio::awaitable<void> {
    rpc_client client;
    co_await client.connect("127.0.0.1:9004");
    auto r1 = co_await client.call<echo_coro>("test");
    assert(r.value == "test");
  };
  sync_wait(rpc_call());
}

这里使用的是asio协程,也是根据社区同学的建议使用asio协程,因为可很容易于和其它的基于asio协程mysql,redis等库结合起来.

特色功能

rest_rpc的特色是支持订阅发布.

客户订阅某个主题,服务端向客户发布.

cpp 复制代码
struct person {
  int id;
  std::string name;
  int age;
};
int main() {
  auto sub = [&]() -> asio::awaitable<void> {
    rpc_client client;
    co_await client.connect("127.0.0.1:9004");
    while (true) {
      auto [ec, result] = co_await client.subscribe<person>("topic1");
      if (ec != rpc_errc::ok) {
        REST_LOG_ERROR << "subscribe failed: " << make_error_code(ec).message();
        break;
      }
      assert(result.name == "tom");
    }
  };
  sync_wait(sub());
}
void publish() {
  rpc_server server("127.0.0.1:9004", 4);
  server.async_start();
  auto pub = [&]() -> asio::awaitable<void> {
    std::string str;
    while (true) {
      std::cin >> str;
      if (str == "quit") {
        break;
      }
      co_await server.publish("topic1", person{1, "tom", 20});
    }
  };
  sync_wait(pub());
}

自定义序化

rest_rpc默认使用的是yalantinglibs.struct_pack,也可按自己的序化库替换它,替换也很简单,定义两个函数即可.比如想替换成msgpack去序化/反序化.

cpp 复制代码
namespace user_codec {
template <typename... Args>
std::string serialize(rest_adl_tag, Args &&...args) {
  in_user_pack = true;
  msgpack::sbuffer buffer(2 * 1024);
  if constexpr (sizeof...(Args) > 1) {
    msgpack::pack(buffer,
    std::forward_as_tuple(std::forward<Args>(args)...));
  } else {
    msgpack::pack(buffer, std::forward<Args>(args)...);
  }
  return std::string(buffer.data(), buffer.size());
}
template <typename T> T deserialize(rest_adl_tag, std::string_view data) {
  try {
    in_user_unpack = true;
    static msgpack::unpacked msg;
    msgpack::unpack(msg, data.data(), data.size());
    return msg.get().as<T>();
  } catch (...) {
    return T{};
  }
}
}
    //user_codec名间

user_codec名字空间下实现序化/反序化函数即可.

零拷贝传输

假如用户希望发送很大的一个数据,可能有数GB,如果按普通的做法,需要先序化,这样就有内存拷贝,rest_rpc针对该场景专门做了优化,

客户调用rpc函数时传入的是std::string_view时,rest_rpc将不会拷贝传入的数据,也不会序化它,而是直接通过套接字发送到服务端.

rpc函数的返回类型std::string_view时,客户不会反序化和内存拷贝收到的响应数据,而是直接返回的是收到的套接字数据.

这样就可实现rpc零拷贝数据发送了,能取得最佳的性能.

性能

rest_rpc的性能比grpcbrpc更好,

相关推荐
郝学胜-神的一滴13 分钟前
Effective STL 第9条:C++容器元素删除技巧详解
开发语言·c++·程序人生·stl
Ma_Hong_Kai22 分钟前
带复选框的combox
c++·mfc
syker1 小时前
太极指令集架构(TCIS)v1.1与主流指令集比较研究报告
c++·架构
jf加菲猫2 小时前
第1章 认识Qt
开发语言·c++·qt·ui
蒋星熠4 小时前
全栈开发实战指南:从架构设计到部署运维
运维·c++·python·系统架构·node.js·devops·c5全栈
杜子不疼.4 小时前
【C++】深入拆解二叉搜索树:从递归与非递归双视角,彻底掌握STL容器的基石
开发语言·c++
天若有情6734 小时前
从零实现轻量级C++ Web框架:SimpleHttpServer入门指南
开发语言·前端·c++·后端·mvc·web应用
mjhcsp6 小时前
C++ 三分查找:在单调与凸函数中高效定位极值的算法
开发语言·c++·算法
Elnaij7 小时前
从C++开始的编程生活(13)——list和浅谈stack、queue
开发语言·c++
深思慎考11 小时前
微服务即时通讯系统(服务端)——用户子服务实现逻辑全解析(4)
linux·c++·微服务·云原生·架构·通讯系统·大学生项目