目录
1. RPC概念
remote process call(简单理解:A主机调用B主机的函数(功能))
当今互联网说的RPC(举例:A主机写python程序 调用B主机的C++函数)
- 远程过程调用(A主机调用B主机的功能)
- A主机调用函数的过程中跟B主机进行若干通信得到运算结果
- B主机接收A主机的请求并进行计算
- 异构、跨语言、跨平台
- 主流的/常用的RPC软件/架构 :
- thrift(Facebook)
- grpc(Google基于protobuf做的RPC)
2. thrift
- 流程
- 写xxx.thrift文件(定义函数原型)
- 生成代码(服务器(B主机)代码–>预留函数的实现)
- 实现预留的函数,启动服务
- 在A主机包含生成的部分代码,编写调用的程序
2.1 写xxx.thrift文件(定义函数原型)
vim plus.thrift
service calculate
{
i32 plus(1:i32 a 2:i32:b)
}
根据plus.thrift产生cpp代码
thrift -r --gen cpp plus.thrift
[root@lwh testthrift]# thrift -r --gen cpp plus.thrift
[root@lwh testthrift]# ls
gen-cpp plus.thrift
[root@lwh testthrift]# cd gen-cpp/
[root@lwh gen-cpp]# ls
calculate.cpp calculate_server.skeleton.cpp plus_constants.h plus_types.h
calculate.h plus_constants.cpp plus_types.cpp
在 calculate_server.skeleton.cpp内实现函数体
2.2 生成代码(服务器(B主机)代码–>预留函数的实现)
在 calculate_server.skeleton.cpp内实现函数体
vim calculate_server.skeleton.cpp
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "calculate.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
class calculateHandler : virtual public calculateIf
{
public:
calculateHandler() // 初始化操作
{
// Your initialization goes here
}
// 把我们的加法函数,实现出来
int32_t plus(const int32_t a, const int32_t b)
{
// Your implementation goes here
// printf("plus\n");
return a + b;
}
};
// 主函数中的代码是通的,不需要更改
int main(int argc, char **argv)
{
/*****
* 可以看出也是三层架构的
* 通道层是:Transport
* 协议层是:protocol
* 业务层是:processor
*/
/****
* 可以看出:
* tcp的socket 9090端口
* TBinaryProtocolFactory:传输协议是 二进制协议
*/
int port = 9090;
::apache::thrift::stdcxx::shared_ptr<calculateHandler> handler(new calculateHandler()); //handler对象,参数是我们自己上面写的对象
::apache::thrift::stdcxx::shared_ptr<TProcessor> processor(new calculateProcessor(handler)); //处理者对象processor,参数是handler对象
::apache::thrift::stdcxx::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
::apache::thrift::stdcxx::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
::apache::thrift::stdcxx::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory); //创建server对象
server.serve(); // 开启服务
return 0;
}
2.3 实现预留的函数,启动服务
把此目录下的cpp文件编译成一个可执行文件,记得加上链接库
[root@lwh gen-cpp]# g++ -std=c++11 *.cpp -o serverplus -lthrift -lssl -lcrypto -L/usr/local/lib64/
[root@lwh gen-cpp]# ls
calculate.cpp calculate.h calculate_server.skeleton.cpp plus_constants.cpp plus_constants.h plus_types.cpp plus_types.h serverplus
[root@lwh gen-cpp]#
[root@lwh gen-cpp]# ./serverplus
./serverplus: error while loading shared libraries: libthrift-0.12.0.so: cannot open shared object file: No such file or directory
[root@lwh gen-cpp]# find / -name libthrift-0.12.0.so
/usr/local/lib/libthrift-0.12.0.so
[root@lwh gen-cpp]# vim /etc/ld.so.conf
[root@lwh gen-cpp]# ldconfig
# 启动serverplus
[root@lwh gen-cpp]# ./serverplus
2.4 在A主机包含生成的部分代码,编写调用的程序
gen-cpp/目录下,除了calculate_server.skeleton.cpp都是客户端程序需要的,
所以将它们拷贝到client/目录下
[root@lwh testthrift]# tree
.
├── client
│ ├── calculate.cpp
│ ├── calculate.h
│ ├── client.cpp
│ ├── plus_constants.cpp
│ ├── plus_constants.h
│ ├── plus_types.cpp
│ └── plus_types.h
├── gen-cpp
│ ├── calculate.cpp
│ ├── calculate.h
│ ├── calculate_server.skeleton.cpp
│ ├── plus_constants.cpp
│ ├── plus_constants.h
│ ├── plus_types.cpp
│ ├── plus_types.h
│ └── serverplus
└── plus.thrift
2 directories, 16 files
[root@lwh testthrift]#
vim client.cpp
#include <iostream>
#include "calculate.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <cstdio>
using std::cout;
using std::endl;
using std::shared_ptr;
int main()
{
// TCP-socket 和服务器通过tcpsocket通信
shared_ptr<apache::thrift::transport::TTransport> socket(new apache::thrift::transport::TSocket("192.168.184.134", 9090));
// 通过TBinaryProtocol的协议来通信,参数是通道对象;协议层对象要绑定一个通道层对象
shared_ptr<apache::thrift::protocol::TProtocol> protocol(new apache::thrift::protocol::TBinaryProtocol(socket));
// 参数是协议对象
calculateClient client(protocol);
// 连接服务器
socket->open();
// 调用
cout << client.plus(1, 1) << endl;
//
getchar();
return 0;
}
// g++ -std=c++11 *.cpp -o clientplus -lthrift -lssl -lcrypto -L/usr/local/lib64/
[root@lwh client]# g++ -std=c++11 *.cpp -o clientplus -lthrift -lssl -lcrypto -L/usr/local/lib64/
[root@lwh client]# ls
calculate.cpp calculate.h client.cpp clientplus plus_constants.cpp plus_constants.h plus_types.cpp plus_types.h
[root@lwh client]# ./clientplus
2 # 执行正常
2.5 演示:python进行rpc调用
上面的例子是C++的client远程调用C++的server;
本次使用python的client调用C++的server
[root@lwh testthrift]# thrift -r --gen py plus.thrift
[root@lwh testthrift]# ls
client gen-cpp gen-py plus.thrift
[root@lwh testthrift]# cd gen-py/
[root@lwh gen-py]# ls
__init__.py plus
[root@lwh gen-py]# cd plus/
[root@lwh plus]# ls
calculate.py calculate-remote constants.py __init__.py ttypes.py
[root@lwh plus]#
这个calculate-remote就是python 的 client的 可执行程序,可以直接调用
[root@lwh plus]# cp calculate-remote ..
[root@lwh plus]# cd ..
[root@lwh gen-py]# ls
calculate-remote __init__.py plus
[root@lwh gen-py]#
指示我们如何传参
[root@lwh gen-py]# ./calculate-remote
Usage: ./calculate-remote [-h host[:port]] [-u url] [-f[ramed]] [-s[sl]] [-novalidate] [-ca_certs certs] [-keyfile keyfile] [-certfile certfile] function [arg1 [arg2...]]
Functions:
i32 plus(i32 a, i32 b)
[root@lwh gen-py]#
实现,正常运行
[root@lwh gen-py]# ./calculate-remote -h 127.0.0.1:9090 plus 1 1
2
[root@lwh gen-py]# ./calculate-remote -h 127.0.0.1:9090 plus 1 10
11
[root@lwh gen-py]# ./calculate-remote -h 127.0.0.1:9090 plus 1 11234
11235
[root@lwh gen-py]#
可以看出使用python调用rpc的服务端,特别方便;
我们以后可以编写rpc服务端的C++代码,然后用python的client直接进行测试(不需要写C++版client了),加快对服务端代码的测试进度。