# buttonrpc_cpp14 **Repository Path**: nirvana-reborn_cpp/buttonrpc_cpp14 ## Basic Information - **Project Name**: buttonrpc_cpp14 - **Description**: 基于zmq的简单RPC实现 - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-07-17 - **Last Updated**: 2021-07-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # buttonrpc > 基于zmq采用C++实现RPC(Remote Procedure Call)远程过程调用,像调用本地的函数一样去调远程函数。 ## [buttonrpc - modern rpc framework for C++] - ZeroMQ 作为网络层 - 使用c++14开发 ## Features - 轻量级,跨平台,简单易用 - 服务端可以绑定自由函数,类成员函数,std::function对象 - 服务端可以绑定参数是任意自定义类型的函数 - 客户端与服务端自动重连机制 - 客户端调用超时选项 ## Dependences - windows:[ZeroMQ](http://zguide.zeromq.org/page:all) - linux:依赖安装:sudo apt-get install libzmq3-dev ## Building - windows vs2015 或者更高版本 - linux 添加编译选项:-std=c++14 或 -std=c++17 ## Usage - 1: 更多例子在目录 example/ 下 - 2: [c++11版本](https://github.com/button-chen/buttonrpc)最多支持5个参数的函数,支持任意多个参数函数请使用[c++14版本](https://github.com/button-chen/buttonrpc_cpp14) - 3: [基于zmq RPC简单C++实现](https://cloud.tencent.com/developer/article/1699189) ## Example server: ```c++ #include "buttonrpc.hpp" int foo(int age, int mm){ return age + mm; } int main() { buttonrpc server; server.as_server(5555); server.bind("foo", foo); server.run(); return 0; } ``` client: ```c++ #include #include "buttonrpc.hpp" int main() { buttonrpc client; client.as_client("127.0.0.1", 5555); int a = client.call("foo", 2, 3).val(); std::cout << "call foo result: " << a << std::endl; system("pause"); return 0; } // output: call foo result: 5 ``` # [RPC](https://blog.csdn.net/u011559046/article/details/115587627) RPC 是需要有三个主要模块:Call ID映射,序列化和反序列化,网络传输。 - ### Call ID映射 > 我们怎么告诉远程机器我们要调用Multiply,而不是Add或者FooBar呢?在本地调用中,函数体是直接通过函数指针来指定的,我们调用Multiply,编译器就自动帮我们调用它相应的函数指针。但是在远程调用中,函数指针是不行的,因为两个进程的地址空间是完全不一样的。所以,在RPC中,所有的函数都必须有自己的一个ID。这个ID在所有进程中都是唯一确定的。客户端在做远程过程调用时,必须附上这个ID。然后我们还需要在客户端和服务端分别维护一个 {函数 <–> Call ID} 的对应表。两者的表不一定需要完全相同,但相同的函数对应的Call ID必须相同。当客户端需要进行远程调用时,它就查一下这个表,找出相应的Call ID,然后把它传给服务端,服务端也通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。 - ### 序列化和反序列化 > 客户端怎么把参数值传给远程的函数呢?在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。但是在远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。甚至有时候客户端和服务端使用的都不是同一种语言(比如服务端用C++,客户端用Java或者Python)。这时候就需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。 - ### 网络传输 > 远程调用往往用在网络上,客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把Call ID和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传回客户端。只要能完成这两者的,都可以作为传输层使用。因此,它所使用的协议其实是不限的,能完成传输就行。尽管大部分RPC框架都使用TCP协议,但其实UDP也可以,而gRPC干脆就用了HTTP2。Java的Netty也属于这层的东西。