gRPC应用C++
1. gRPC简述
RPC,远程方法调用,就是像调用本地方法一样调用远程方法。
gRPC是Google实现的一种RPC框架,基于HTTP/2标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持。
基本原理:在服务端提供方法,并运行服务器监听客户端请求;客户端调用RPC方法,gRPC客户端向服务端发送请求,并将结果返回给客户端调用函数。
gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如 JSON)。推荐使用protobuf v3。
github:https://github.com/grpc/grpc
RPC框架要做到的最基本的三件事:
1)服务端如何确定客户端要调用的函数;
在远程调用中,客户端和服务端分别维护一个【ID->函数】的对应表, ID在所有进程中都是唯一确定的。客户端在做远程过程调用时,附上这个ID,服务端通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。
2)如何进行序列化和反序列化;
客户端和服务端交互时将参数或结果转化为字节流在网络中传输,那么数据转化为字节流的或者将字节流转换成能读取的固定格式时就需要进行序列化和反序列化,序列化和反序列化的速度也会影响远程调用的效率。
3)如何进行网络传输(选择何种网络协议);
多数RPC框架选择TCP作为传输协议,也有部分选择HTTP。如gRPC使用HTTP2。不同的协议各有利弊。TCP更加高效,而HTTP在实际应用中更加的灵活。
REST与RPC应用场景
REST和RPC都常用于微服务架构中。
1)HTTP相对更规范,更标准,更通用,无论哪种语言都支持http协议。如果你是对外开放API,例如开放平台,外部的编程语言多种多样,你无法拒绝对每种语言的支持,现在开源中间件,基本最先支持的几个协议都包含RESTful。
2)RPC 框架作为架构微服务化的基础组件,它能大大降低架构微服务化的成本,提高调用方与服务提供方的研发效率,屏蔽跨进程调用函数(服务)的各类复杂细节。让调用方感觉就像调用本地函数一样调用远端函数、让服务提供方感觉就像实现一个本地函数一样来实现服务。
REST调用及测试都很方便,RPC就显得有点繁琐,但是RPC的效率是毋庸置疑的,所以建议在多系统之间的内部调用采用RPC。对外提供的服务,Rest更加合适。
2. 安装
$ git clone https://github.com/grpc/grpc.git $ cd grpc $ git submodule update --init $make $sudo make install
注:执行submodule时时间较长
[INSTALL] Installing public C headers [MAKE] Generating cache.mk [STRIP] Stripping libaddress_sorting.a [STRIP] Stripping libgpr.a [STRIP] Stripping libgrpc.a [STRIP] Stripping libgrpc_cronet.a [STRIP] Stripping libgrpc_unsecure.a [INSTALL] Installing C pkg-config files [INSTALL] Installing libaddress_sorting.a [INSTALL] Installing libgpr.a [INSTALL] Installing libgrpc.a [INSTALL] Installing libgrpc_cronet.a [INSTALL] Installing libgrpc_unsecure.a [STRIP] Stripping libaddress_sorting.so.7.0.0 [STRIP] Stripping libgpr.so.7.0.0 [STRIP] Stripping libgrpc.so.7.0.0 [STRIP] Stripping libgrpc_cronet.so.7.0.0 [STRIP] Stripping libgrpc_unsecure.so.7.0.0 [INSTALL] Installing libaddress_sorting.so.7.0.0 [INSTALL] Installing libgpr.so.7.0.0 [INSTALL] Installing libgrpc.so.7.0.0 [INSTALL] Installing libgrpc_cronet.so.7.0.0 [INSTALL] Installing libgrpc_unsecure.so.7.0.0 [INSTALL] Installing public C++ headers [AR] Creating /home/wang/repo/grpc/libs/opt/libgrpc_plugin_support.a [HOSTCXX] Compiling src/compiler/cpp_plugin.cc [HOSTLD] Linking /home/wang/repo/grpc/bins/opt/grpc_cpp_plugin [HOSTCXX] Compiling src/compiler/csharp_plugin.cc [HOSTLD] Linking /home/wang/repo/grpc/bins/opt/grpc_csharp_plugin [HOSTCXX] Compiling src/compiler/node_plugin.cc [HOSTLD] Linking /home/wang/repo/grpc/bins/opt/grpc_node_plugin [HOSTCXX] Compiling src/compiler/objective_c_plugin.cc [HOSTLD] Linking /home/wang/repo/grpc/bins/opt/grpc_objective_c_plugin [HOSTCXX] Compiling src/compiler/php_plugin.cc [HOSTLD] Linking /home/wang/repo/grpc/bins/opt/grpc_php_plugin [HOSTCXX] Compiling src/compiler/python_plugin.cc [HOSTLD] Linking /home/wang/repo/grpc/bins/opt/grpc_python_plugin [HOSTCXX] Compiling src/compiler/ruby_plugin.cc [HOSTLD] Linking /home/wang/repo/grpc/bins/opt/grpc_ruby_plugin [PROTOC] Generating protobuf CC file from src/proto/grpc/channelz/channelz.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/channelz/channelz.proto [PROTOC] Generating protobuf CC file from src/proto/grpc/health/v1/health.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/health/v1/health.proto [PROTOC] Generating protobuf CC file from src/proto/grpc/testing/echo_messages.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/testing/echo_messages.proto [PROTOC] Generating protobuf CC file from src/proto/grpc/testing/simple_messages.proto [PROTOC] Generating protobuf CC file from src/proto/grpc/testing/echo.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/testing/simple_messages.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/testing/echo.proto [PROTOC] Generating protobuf CC file from src/proto/grpc/testing/duplicate/echo_duplicate.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/testing/duplicate/echo_duplicate.proto [PROTOC] Generating protobuf CC file from src/proto/grpc/core/stats.proto [CXX] Compiling /home/wang/repo/grpc/gens/src/proto/grpc/core/stats.pb.cc [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/core/stats.proto [CXX] Compiling /home/wang/repo/grpc/gens/src/proto/grpc/core/stats.grpc.pb.cc [CXX] Compiling src/cpp/util/core_stats.cc [AR] Creating /home/wang/repo/grpc/libs/opt/libgrpc++_core_stats.a [PROTOC] Generating protobuf CC file from src/proto/grpc/testing/payloads.proto [PROTOC] Generating protobuf CC file from src/proto/grpc/testing/stats.proto [PROTOC] Generating protobuf CC file from src/proto/grpc/testing/control.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/testing/payloads.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/testing/stats.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/testing/control.proto [PROTOC] Generating protobuf CC file from src/proto/grpc/testing/messages.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/testing/messages.proto [PROTOC] Generating protobuf CC file from src/proto/grpc/testing/benchmark_service.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/testing/benchmark_service.proto [PROTOC] Generating protobuf CC file from src/proto/grpc/testing/report_qps_scenario_service.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/testing/report_qps_scenario_service.proto [PROTOC] Generating protobuf CC file from src/proto/grpc/testing/worker_service.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/testing/worker_service.proto [CXX] Compiling src/cpp/codegen/codegen_init.cc [AR] Creating /home/wang/repo/grpc/libs/opt/libgrpc++.a [AR] Creating /home/wang/repo/grpc/libs/opt/libgrpc++_cronet.a [PROTOC] Generating protobuf CC file from src/proto/grpc/status/status.proto [CXX] Compiling /home/wang/repo/grpc/gens/src/proto/grpc/status/status.pb.cc [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/status/status.proto [CXX] Compiling /home/wang/repo/grpc/gens/src/proto/grpc/status/status.grpc.pb.cc [CXX] Compiling src/cpp/util/error_details.cc [AR] Creating /home/wang/repo/grpc/libs/opt/libgrpc++_error_details.a [PROTOC] Generating protobuf CC file from src/proto/grpc/reflection/v1alpha/reflection.proto [GRPC] Generating gRPC's protobuf service CC file from src/proto/grpc/reflection/v1alpha/reflection.proto [CXX] Compiling src/cpp/ext/proto_server_reflection.cc [CXX] Compiling src/cpp/ext/proto_server_reflection_plugin.cc [CXX] Compiling /home/wang/repo/grpc/gens/src/proto/grpc/reflection/v1alpha/reflection.pb.cc [CXX] Compiling /home/wang/repo/grpc/gens/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc [AR] Creating /home/wang/repo/grpc/libs/opt/libgrpc++_reflection.a [AR] Creating /home/wang/repo/grpc/libs/opt/libgrpc++_unsecure.a [CXX] Compiling src/cpp/server/channelz/channelz_service.cc [CXX] Compiling src/cpp/server/channelz/channelz_service_plugin.cc [CXX] Compiling /home/wang/repo/grpc/gens/src/proto/grpc/channelz/channelz.pb.cc [CXX] Compiling /home/wang/repo/grpc/gens/src/proto/grpc/channelz/channelz.grpc.pb.cc [AR] Creating /home/wang/repo/grpc/libs/opt/libgrpcpp_channelz.a [STRIP] Stripping libgrpc++.a [STRIP] Stripping libgrpc++_cronet.a [STRIP] Stripping libgrpc++_error_details.a [STRIP] Stripping libgrpc++_reflection.a [STRIP] Stripping libgrpc++_unsecure.a [STRIP] Stripping libgrpcpp_channelz.a [INSTALL] Installing C++ pkg-config files [INSTALL] Installing libgrpc++.a [INSTALL] Installing libgrpc++_cronet.a [INSTALL] Installing libgrpc++_error_details.a [INSTALL] Installing libgrpc++_reflection.a [INSTALL] Installing libgrpc++_unsecure.a [INSTALL] Installing libgrpcpp_channelz.a [LD] Linking /home/wang/repo/grpc/libs/opt/libgrpc++.so.1.20.0 [LD] Linking /home/wang/repo/grpc/libs/opt/libgrpc++_cronet.so.1.20.0 [LD] Linking /home/wang/repo/grpc/libs/opt/libgrpc++_error_details.so.1.20.0 [LD] Linking /home/wang/repo/grpc/libs/opt/libgrpc++_reflection.so.1.20.0 [LD] Linking /home/wang/repo/grpc/libs/opt/libgrpc++_unsecure.so.1.20.0 [LD] Linking /home/wang/repo/grpc/libs/opt/libgrpcpp_channelz.so.1.20.0 [STRIP] Stripping libgrpc++.so.1.20.0 [STRIP] Stripping libgrpc++_cronet.so.1.20.0 [STRIP] Stripping libgrpc++_error_details.so.1.20.0 [STRIP] Stripping libgrpc++_reflection.so.1.20.0 [STRIP] Stripping libgrpc++_unsecure.so.1.20.0 [STRIP] Stripping libgrpcpp_channelz.so.1.20.0 [INSTALL] Installing libgrpc++.so.1.20.0 [INSTALL] Installing libgrpc++_cronet.so.1.20.0 [INSTALL] Installing libgrpc++_error_details.so.1.20.0 [INSTALL] Installing libgrpc++_reflection.so.1.20.0 [INSTALL] Installing libgrpc++_unsecure.so.1.20.0 [INSTALL] Installing libgrpcpp_channelz.so.1.20.0 [INSTALL] Installing grpc protoc plugins [INSTALL] Installing root certificates
安装的文件包含:bin,include,lib,share(根证书)。
3. 应用
examples下有各语言版本的示例,examples/protoc是protoc示例文件。
如下演示的是helloworld示例,examples中不仅支持同步调用,还支持异步调用。
1. proto文件定义RPC方法及参数
helloworld.proto
syntax = "proto3"; option java_package = "io.grpc.examples"; package helloworld; // The greeter service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; }
编译生成c++源文件(grpc和应用)
protoc --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` helloworld.proto
protoc --cpp_out=. helloworld.proto
2. server端代码
#include <iostream> #include <memory> #include <string> #include <grpcpp/grpcpp.h> #ifdef BAZEL_BUILD #include "examples/protos/helloworld.grpc.pb.h" #else #include "helloworld.grpc.pb.h" #endif using grpc::Server; using grpc::ServerBuilder; using grpc::ServerContext; using grpc::Status; using helloworld::HelloRequest; using helloworld::HelloReply; using helloworld::Greeter; // Logic and data behind the server's behavior. class GreeterServiceImpl final : public Greeter::Service { Status SayHello(ServerContext* context, const HelloRequest* request, HelloReply* reply) override { std::string prefix("Hello "); reply->set_message(prefix + request->name()); return Status::OK; } }; void RunServer() { std::string server_address("0.0.0.0:50051"); GreeterServiceImpl service; ServerBuilder builder; // Listen on the given address without any authentication mechanism. builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); // Register "service" as the instance through which we'll communicate with // clients. In this case it corresponds to an *synchronous* service. builder.RegisterService(&service); // Finally assemble the server. std::unique_ptr<Server> server(builder.BuildAndStart()); std::cout << "Server listening on " << server_address << std::endl; // Wait for the server to shutdown. Note that some other thread must be // responsible for shutting down the server for this call to ever return. server->Wait(); } int main(int argc, char** argv) { RunServer(); return 0; }
编译执行:
g++ -o server helloworld.pb.cc helloworld.grpc.pb.cc server.cc -L/usr/local/lib `pkg-config --cflags protobuf grpc` -std=c++11 `pkg-config --libs protobuf grpc++ grpc` -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed -ldl $ ./server Server listening on 0.0.0.0:50051
3. client端代码
#include <iostream> #include <memory> #include <string> #include <grpcpp/grpcpp.h> #ifdef BAZEL_BUILD #include "examples/protos/helloworld.grpc.pb.h" #else #include "helloworld.grpc.pb.h" #endif using grpc::Channel; using grpc::ClientContext; using grpc::Status; using helloworld::HelloRequest; using helloworld::HelloReply; using helloworld::Greeter; class GreeterClient { public: GreeterClient(std::shared_ptr<Channel> channel) : stub_(Greeter::NewStub(channel)) {} // Assembles the client's payload, sends it and presents the response back // from the server. std::string SayHello(const std::string& user) { // Data we are sending to the server. HelloRequest request; request.set_name(user); // Container for the data we expect from the server. HelloReply reply; // Context for the client. It could be used to convey extra information to // the server and/or tweak certain RPC behaviors. ClientContext context; // The actual RPC. Status status = stub_->SayHello(&context, request, &reply); // Act upon its status. if (status.ok()) { return reply.message(); } else { std::cout << status.error_code() << ": " << status.error_message() << std::endl; return "RPC failed"; } } private: std::unique_ptr<Greeter::Stub> stub_; }; int main(int argc, char** argv) { // Instantiate the client. It requires a channel, out of which the actual RPCs // are created. This channel models a connection to an endpoint (in this case, // localhost at port 50051). We indicate that the channel isn't authenticated // (use of InsecureChannelCredentials()). GreeterClient greeter(grpc::CreateChannel( "127.0.0.1:50051", grpc::InsecureChannelCredentials())); std::string user("world"); std::string reply = greeter.SayHello(user); std::cout << "Greeter received: " << reply << std::endl; return 0; }
编译执行:
g++ -o client helloworld.pb.cc helloworld.grpc.pb.cc client.cc -L/usr/local/lib `pkg-config --cflags protobuf grpc` -std=c++11 `pkg-config --libs protobuf grpc++ grpc` -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed -ldl $ ./client Greeter received: Hello world
参考:
1. https://www.grpc.io/docs/ 官网
2. http://doc.oschina.net/grpc 中文官网
4. Grpc+Grpc Gateway实践一 介绍与环境安装
5. grpc 的安装和使用
7. 实现一个 RESTful API 服务器 RSET和RPC比较
8. gRPC(HTTP / 2)比使用HTTP / 2的REST更快吗? 默认情况下,gRPC不比HTTP / REST更快,但它为您提供了更快的工具。有些事情对于REST来说很难或不可能做到。