gRPC应用C++

Wesley13
• 阅读 802

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应用C++  

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时时间较长

gRPC应用C++ gRPC应用C++

[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

install log

安装的文件包含: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 中文官网

3. 花了一个星期,我终于把RPC框架整明白了!

4. Grpc+Grpc Gateway实践一 介绍与环境安装

5. grpc 的安装和使用

6. 面试问题:REST与RPC区别?

7.  实现一个 RESTful API 服务器 RSET和RPC比较

8. gRPC(HTTP / 2)比使用HTTP / 2的REST更快吗?  默认情况下,gRPC不比HTTP / REST更快,但它为您提供了更快的工具。有些事情对于REST来说很难或不可能做到。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
暗箭伤人 暗箭伤人
7个月前
【www.ithunter.club】 20230922下午
不容易的2023年,我们一起努力【www.ithunter.club】(2023092208:00:00.8872062023092216:00:00.887206)1.人事招聘专员数名(可选远程或入职)2.招聘向坐标东京Yahoo、Shift、L
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这