vlambda博客
学习文章列表

用C++实现一个RPC框架

https://zhuanlan.zhihu.com/p/33298916

RPC(Remote Procedure Call)框架使得一个进程可以调用另一个进程里的procedure, 

是编写网络应用的基础设施. 我所知道的RPC框架有grpc, brpc, libjson-rpc-cpp. 

大致研究了RPC的原理以后, 我实现了一个简单的RPC框架

, 具有如下特性:

  • 使用JSON数据格式作为序列化/反序列化方案, 实现了JSON-RPC 2.0 specification.


  • 客户端支持异步RPC, 也可以通过线程同步达到同步RPC的效果.


  • 服务端支持多线程RPC, 即用户可以将RPC请求交给另一个线程(或者线程池)

  • 去执行, 这样IO线程就可以立刻开始等待下一个请求.


  • 通唯一定义一个procedure. 一个TCP端口可以对外提供多个service, 一个service可以有多个method.




RPC框架的结构

RPC框架的结构如上图所示, 自底向上分别有网络库, JSON解析器/生成器, 客户端/服务端stub, 此外还有一个独立的程序stub generator, 用于生成stub供用户直接使用. 下面就这几个组件分别说明.

网络库

网络库位于框架底层, 向下封装Linux socket API, 向上提供消息回调. 此外, 网络库还具有定时器, 线程池, 日志输出等功能. 我从去年9月份开始造轮子, 目前实现了一个基于Reactor模式的多线程网络库. 代码参考了

@陈硕

 的 muduo 库, 他的书<Linux服务端多线程编程>和课程对我帮助也很大.


tinyev: A multithreaded C++ network library github.com用C++实现一个RPC框架

我还有一篇博客讲了网络库的实现, 感兴趣的同学可以看看.

JSON解析器/生成器

起初照着 

@Milo Yip

 的C语言JSON解析器实现教程写了一个简单版本, 但后来放到RPC框架中发现不太好用: 首先是API过于简陋, 而且没有C++的RAII支持; 再者生成器部分功能不灵活, 没法生造一个JSON Document, 一波set操作再输出字符串. 然后我发现了RapidJSON, 同样是Milo的作品. 了解了RapidJSON的设计思路以后, 我也实现了一个简单的解析器, 支持DOM和SAX两种风格的API, 大约2000行代码.


jackson: A simple and fast JSON parser/generator github.com用C++实现一个RPC框架

对于解析器的设计思路, 贴一张RapidJSON文档里的图:

用C++实现一个RPC框架

Stub generator

service stub有两个功能:

  1. 将request JSON object里的调用参数提取出来, 并转换成普通的函数调用

  2. 把函数的的返回值包装成一个response JSON object, 并通过网络库发送出去

相应的client stub也有两个功能:

  1. 把函数参数包装到request JSON object中, 并通过网络库发送出去

  2. 把response JSON object里的返回值/错误码提取出来, 传递给用户回调

对于不同的 用C++实现一个RPC框架 , 这些工作都有所区别, 而且很繁琐, 手写容易出错. 幸运的是它们大同小异, 可以用程序自动生成. 首先, 我们看看一个echo service的配置文件:

{
"name": "Echo",
"rpc": [
{
"name": "Echo",
"params": { "message": "hello!!" },
"returns": "string"
}
]
}

翻译成中文就是: 

定义一个名为Echo的service, 该service有一个名为Echo的method, 该method接收一个名为message字符串参数并返回一个字符串. 利用这些信息我们就可以生成stub了. 具体方法就是替换的stub模板文件中的关键字,

例如将 用C++实现一个RPC框架 关键字替换成  . 由于JSON文本的可读性高, 我们可以直接在wireshark里看到RPC的调用过程:

84 {"jsonrpc":"2.0","method":"Arithmetic.Add","params":{"lhs":10.0,"rhs":3.0},"id":0}
40 {"jsonrpc":"2.0","id":0,"result":13.0}
83 {"jsonrpc":"2.0","method":"Arithmetic.Add","params":{"lhs":0.0,"rhs":2.0},"id":1}
39 {"jsonrpc":"2.0","id":1,"result":2.0}
83 {"jsonrpc":"2.0","method":"Arithmetic.Add","params":{"lhs":3.0,"rhs":6.0},"id":2}
39 {"jsonrpc":"2.0","id":2,"result":9.0}

最后

RPC框架的代码在

jrpc: A JSON-RPC implementation github.com



理解动态代理及动态代理在RPC中的应用

https://blog.csdn.net/nyyjs/article/details/77850523

什么是RPC?原理是什么?如何实现一个 RPC 框架?