用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框架的结构如上图所示, 自底向上分别有网络库, JSON解析器/生成器, 客户端/服务端stub, 此外还有一个独立的程序stub generator, 用于生成stub供用户直接使用. 下面就这几个组件分别说明.
网络库
网络库位于框架底层, 向下封装Linux socket API, 向上提供消息回调. 此外, 网络库还具有定时器, 线程池, 日志输出等功能. 我从去年9月份开始造轮子, 目前实现了一个基于Reactor模式的多线程网络库. 代码参考了
@陈硕
的 muduo 库, 他的书<Linux服务端多线程编程>和课程对我帮助也很大.
tinyev: A multithreaded C++ network library github.com
我还有一篇博客讲了网络库的实现, 感兴趣的同学可以看看.
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
对于解析器的设计思路, 贴一张RapidJSON文档里的图:
Stub generator
service stub有两个功能:
将request JSON object里的调用参数提取出来, 并转换成普通的函数调用
把函数的的返回值包装成一个response JSON object, 并通过网络库发送出去
相应的client stub也有两个功能:
把函数参数包装到request JSON object中, 并通过网络库发送出去
把response JSON object里的返回值/错误码提取出来, 传递给用户回调
对于不同的 , 这些工作都有所区别, 而且很繁琐, 手写容易出错. 幸运的是它们大同小异, 可以用程序自动生成. 首先, 我们看看一个echo service的配置文件:
{
"name": "Echo",
"rpc": [
{
"name": "Echo",
"params": { "message": "hello!!" },
"returns": "string"
}
]
}
翻译成中文就是:
定义一个名为Echo的service, 该service有一个名为Echo的method, 该method接收一个名为message字符串参数并返回一个字符串. 利用这些信息我们就可以生成stub了. 具体方法就是替换的stub模板文件中的关键字,
例如将 关键字替换成 . 由于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