c++grpc详解

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一.简介

  • gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言
    版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C,
    PHP 和 C# 支持.
  • gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等 特性。这
    些特性使得其在移动设备上表现更好,更省电和节省空间占用。
  • 在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法, 使得您
    能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念: 定义一个服务,指
    定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口, 并运行一个 gRPC 服务器来
    处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法
    在这里插入图片描述

支持的语言

c++ java Objective-C python Ruby Go C# Node.js

使用场景

  • 低延迟,高扩展的分布式系统
  • 与云服务器通信
  • 设计与语言无关的协议
  • 分层设计

特点

  • 跨平台,跨语言
  • 协议自由,可根据需求自己选择协议(json, XML,thirft)
  • 支持同步和异步
  • 可以取消请求和设置超时
  • 流处理,可以处理大型数据集

二.传输原理

在这里插入图片描述

  • 使用stub代理使用protobuf将数据序列化,再使用http2.0将数据发送给tcp
  • 选择使用HTTP2.0和protobuf大大提升了传输效率
  • 在这里插入图片描述

protobuf传输

  • protobuf是Goole开发的一种跨语言,跨平台,可扩展的序列化数据协议
  • protobuf传输速度快比JOSN,采用二进制序列化方式,
  • 早期的rpc使用JSON传输,现在基本都采用Protobuf的二进制传输
  • 差别在于Json是适合人阅读,protobuf适合机器

HTTP2.0

在这里插入图片描述

http2.0,相对于http1.0有以下几个改进:

  • 未改变HTTP语义
  • 引入帧,流的概念,可以区分多个请求和相应
  • 借助帧和流可以实现多路复用
  • 使用二进制编码,降低header空间占用

流和帧

  • HTTP1.1存在无法区分请求,只能串行发送
  • HTTP2.0提出流的概念,每个请求对应一个ID,来区分不同请求
  • 基于流又提出帧的概念,将数据分成多个帧,分割传输,而这多个帧都属于一个流
  • 通过这种二进制乱序的模式,解决了HTTP1.1的核心痛点,通过这种复用tcp连接的方式,不用再同时建立多个连接,提升了TCP利用效率

三.grpc的四种模式

1.一元RPC模式

一元 RPC 模式也被称为简单 RPC 模式。在该模式中,当客户端调用服务器端的远程方法时,客户端发送请求至服务器端并获得一个响应,与响应一起发送的还有状态细节以及元数据。

2.服务端流

在一元 RPC 模式中,gRPC 服务器端和 gRPC 客户端在通信时始终只有一个请求和一个响应。在服务器端流 RPC模式中,服务器端在接收到客户端的请求消息后,会发回一个响应的序列。这种多个响应所组成的序列也被称为“流”。在将所有的服务器端响应发送完毕之后,服务器端会以元数据的形式将其状态发送给客户端,从而标记流的结束。

  • 在protoc文件中定义方式
    在这里插入图片描述
  • 客户端流式代码
std::unique ptr<ClientReader<Feature>>reader(stub ->ListFeatures(&context,rect));
while(reader->Read(&feature))
{
std::cout<<"Found feature called "<< feature.name()
<<" ata"<<feature.location().latitude()
<<feature.location().longitude() << std::end
}
Status status =reader->Finish();
if(status.ok()){
std::cout<<"ListFeatures rpc succeeded."<< std::endl;
}else {
ListFeatures rpc failed."<< std::endl;
}
  • 服务端流式代码
StatusRecordRoute(Servercontext context,const routeguide::Rectangle rectangle,ServerWrite<Feature>*write)override
{
for (const Feature& f:featurelist )
{
writer->Write(f);
}
return status::OK;//流结束
}

3.客户端流

在客户端流 RPC模式中,客户端会发送多个请求给服务器端,而不再是单个请求。服务器端则会发送一个响应给客户端。但是,服务器端不一定要等到从客户端接收到所有消息后才发送响应。基于这样的逻辑,我们可以在接收到流中的一条消息或几条消息之后就发送响应,也可以在读取完流中的所有消息之后再发送响应。

  • 在protoc文件中定义方式
    在这里插入图片描述
  • 客户端代码
std::unique ptr<clientWriter<Point>>writer(stub ->RecordRoute(&context,&stats);
for(int i=0;i< kPoints; i++){
//

业务处理
//
writer->Write(f.location()
)

writer->WritesDone();
Status status = writer->Finish():
  • 服务端代码
StatusRecordRoute(Servercontextcontext,ServerReader<Point>*reader,,RouteSummary*summary) override{

while(reader->Read(&point)){
处理业务
}
return status::OK;//流结束
}

4.双向流

在双向流 RPC 模式中,客户端以消息流的形式发送请求到服务器端,服务器端也以消息流的形式进行响应。调用必须由客户端发起,但在此之后,通信完全基于gRPC客户端和服务器端的应用程序逻辑。
需要一个接受线程和发送线程·

  • 在protoc文件中定义方式在这里插入图片描述
Status RouteChat(Servercontext* context,ServerReaderWriter<RouteNote,RouteNote>* stream)override
{
RouteNote note;
while(stream->Read(&note)){
//业务处理

sheam->Write(n);
}
return status::0K;
}

四.基本流程

在这里插入图片描述
基本流程代码以及一元模式看grpc的简单使用

<think>我们正在讨论如何在项目中使用C++gRPC进行远程过程调用。根据引用内容,我们可以总结出以下关键点:1.gRPC是一个高性能、开源的RPC框架,使用ProtocolBuffers作为接口定义语言(IDL)和消息序列化工具。2.使用流程包括:定义.proto文件、生成代码、实现服务端和客户端。3.环境搭建和编译配置是关键步骤(如引用[3][4]所述)。现在,我们需要提供实际应用案例和使用方法。实际应用案例:-微服务架构:服务之间的通信,例如订单服务调用支付服务。-分布式系统:跨语言通信,例如用C++编写的核心算法服务被Python或Java的前端调用。-云原生应用:在Kubernetes中部署gRPC服务,实现负载均衡和健康检查。使用方法步骤:1.定义服务接口(.proto文件):例如,定义一个简单的计算服务,包含加法和乘法方法。2.生成代码:使用protoc编译器生成服务端和客户端代码。3.实现服务端:继承生成的基类,实现服务方法。4.实现客户端:使用生成的存根(stub)调用服务端方法。5.运行服务。下面我们详细展开,并给出代码示例。###步骤1:定义服务接口(.proto文件)创建一个`calculator.proto`文件:```protobufsyntax="proto3";packagecalculator;serviceCalculator{rpcAdd(AddRequest)returns(AddResponse){}rpcMultiply(MultiplyRequest)returns(MultiplyResponse){}}messageAddRequest{int32a=1;int32b=2;}messageAddResponse{int32result=1;}messageMultiplyRequest{int32a=1;int32b=2;}messageMultiplyResponse{int32result=1;}```###步骤2:生成代码使用protoc编译器生成代码(需要安装grpc和protobuf):```bashprotoc--grpc_out=.--cpp_out=.--plugin=protoc-gen-grpc=`whichgrpc_cpp_plugin`calculator.proto```这将生成`calculator.pb.h`、`calculator.pb.cc`、`calculator.grpc.pb.h`、`calculator.grpc.pb.cc`四个文件。###步骤3:实现服务端在服务端项目中,创建`server.cpp`,实现Calculator服务:```cpp#include<iostream>#include<memory>#include<string>#include<grpcpp/grpcpp.h>#include"calculator.grpc.pb.h"usinggrpc::Server;usinggrpc::ServerBuilder;usinggrpc::ServerContext;usinggrpc::Status;usingcalculator::Calculator;usingcalculator::AddRequest;usingcalculator::AddResponse;usingcalculator::MultiplyRequest;usingcalculator::MultiplyResponse;classCalculatorServiceImplfinal:publicCalculator::Service{StatusAdd(ServerContext*context,constAddRequest*request,AddResponse*reply)override{reply->set_result(request->a()+request->b());returnStatus::OK;}StatusMultiply(ServerContext*context,constMultiplyRequest*request,MultiplyResponse*reply)override{reply->set_result(request->a()*request->b());returnStatus::OK;}};voidRunServer(){std::stringserver_address("0.0.0.0:50051");CalculatorServiceImplservice;ServerBuilderbuilder;builder.AddListeningPort(server_address,grpc::InsecureServerCredentials());builder.RegisterService(&service);std::unique_ptr<Server>server(builder.BuildAndStart());std::cout<<"Serverlisteningon"<<server_address<<std::endl;server->Wait();}intmain(){RunServer();return0;}```###步骤4:实现客户端在客户端项目中,创建`client.cpp`:```cpp#include<iostream>#include<memory>#include<string>#include<grpcpp/grpcpp.h>#include"calculator.grpc.pb.h"usinggrpc::Channel;usinggrpc::ClientContext;usinggrpc::Status;usingcalculator::Calculator;usingcalculator::AddRequest;usingcalculator::AddResponse;usingcalculator::MultiplyRequest;usingcalculator::MultiplyResponse;classCalculatorClient{public:CalculatorClient(std::shared_ptr<Channel>channel):stub_(Calculator::NewStub(channel)){}intAdd(inta,intb){AddRequestrequest;request.set_a(a);request.set_b(b);AddResponseresponse;ClientContextcontext;Statusstatus=stub_->Add(&context,request,&response);if(status.ok()){returnresponse.result();}else{std::cout<<"RPCfailed:"<<status.error_message()<<std::endl;return-1;}}intMultiply(inta,intb){MultiplyRequestrequest;request.set_a(a);request.set_b(b);MultiplyResponseresponse;ClientContextcontext;Statusstatus=stub_->Multiply(&context,request,&response);if(status.ok()){returnresponse.result();}else{std::cout<<"RPCfailed:"<<status.error_message()<<std::endl;return-1;}}private:std::unique_ptr<Calculator::Stub>stub_;};intmain(){CalculatorClientclient(grpc::CreateChannel("localhost:50051",grpc::InsecureChannelCredentials()));intsum=client.Add(3,4);std::cout<<"3+4="<<sum<<std::endl;intproduct=client.Multiply(3,4);std::cout<<"3*4="<<product<<std::endl;return0;}```###步骤5:编译运行-编译服务端和客户端程序,需要链接gRPC和protobuf库。-先运行服务端,再运行客户端。###实际应用中的注意事项1.**错误处理**:在服务端和客户端都要进行错误处理。2.**安全性**:在生产环境中应使用SSL/TLS加密(如引用[5]提到,官方文档有详细说明)。3.**异步调用**:对于高性能场景,可以使用异步接口(引用[1][5]提到高级应用技巧)。4.**超时控制**:客户端可以设置超时时间。5.**元数据传递**:用于传递认证信息等。以上就是一个完整的C++gRPC应用案例。在实际项目中,可以根据业务需求扩展服务定义,并处理更复杂的业务逻辑。§§相关问题§§1.如何保证gRPC通信的安全性?2.gRPC支持哪些类型的调用模式(如单向、流式)?3.在分布式系统中如何处理gRPC服务的负载均衡?4.gRPC和传统的RESTfulAPI相比有哪些优势?</think>### C++ gRPC在项目中的实际应用案例与使用方法 #### 一、实际应用案例 1. **微服务通信** 在分布式系统中,C++微服务使用gRPC实现跨节点通信。例如订单服务调用库存服务检查库存量[^1]: ```protobuf service InventoryService { rpc CheckStock(StockRequest) returns (StockResponse); } ``` 2. **游戏服务器架构** 游戏逻辑服务器(C++)通过gRPC与用户匹配服务器通信,实现低延迟的玩家匹配: ```cpp // 客户端调用匹配服务 MatchRequest request; request.set_player_id(1001); MatchResponse response = stub_->FindMatch(&context, request); ``` 3. **金融交易系统** 高频交易引擎(C++)使用gRPC流式接口传输实时行情数据: ```protobuf service MarketData { rpc SubscribeTicks(SubscribeReq) returns (stream TickData); } ``` 4. **物联网设备控制** C++编写的边缘计算网关通过gRPC接收云端的控制指令: ```cpp // 服务端实现 Status SetDeviceState(ServerContext* ctx, const Command* req, Response* res) { actuator_.execute(req->command_code()); // 执行物理设备操作 res->set_success(true); } ``` #### 二、使用流程详解(基于Visual Studio) 1. **环境配置** - 安装vcpkg:`vcpkg install grpc protobuf` - VS项目配置包含目录:`grpc/include`、`protobuf/include`[^3][^4] - 库目录添加:`grpc/lib`、`protobuf/lib` 2. **定义服务接口(.proto文件)** ```protobuf syntax = "proto3"; service FileService { rpc Upload(stream Chunk) returns (UploadStatus); // 流式上传 rpc Download(FileRequest) returns (stream Chunk); // 流式下载 } message Chunk { bytes content = 1; } ``` 3. **生成代码** 使用protoc编译器生成桩代码: ```bash protoc --grpc_out=. --cpp_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin.exe file_service.proto ``` 生成`file_service.grpc.pb.h`和`file_service.pb.cc`[^5] 4. **服务端实现** ```cpp #include "file_service.grpc.pb.h" class FileServiceImpl final : public FileService::Service { Status Upload(ServerContext* ctx, ServerReader<Chunk>* reader, UploadStatus* status) override { Chunk chunk; while (reader->Read(&chunk)) { file.Write(chunk.content()); // 写入本地文件 } status->set_bytes_received(file.Size()); return Status::OK; } }; ``` 5. **客户端调用** ```cpp // 流式上传示例 ClientContext ctx; UploadStatus status; auto writer = stub_->Upload(&ctx, &status); for (auto& chunk : file_chunks) { if (!writer->Write(chunk)) break; // 分块发送 } writer->WritesDone(); ``` 6. **启动服务** ```cpp ServerBuilder builder; builder.AddListeningPort("0.0.0.0:50051", grpc::InsecureServerCredentials()); builder.RegisterService(&file_service); std::unique_ptr<Server> server(builder.BuildAndStart()); server->Wait(); // 阻塞等待请求 ``` #### 三、性能优化技巧 1. **复用gRPC通道** 创建一次`grpc::CreateChannel`并复用,避免连接开销: ```cpp static auto channel = grpc::CreateChannel("server:50051", grpc::InsecureChannelCredentials()); ``` 2. **异步接口** 高并发场景使用异步桩: ```cpp CompletionQueue cq; stub_->AsyncUpload(&ctx, &response, &cq, tag); // 非阻塞调用 ``` 3. **连接池配置** 设置通道参数: ```cpp ChannelArguments args; args.SetMaxReceiveMessageSize(100 * 1024 * 1024); // 100MB消息支持 ``` 4. **负载均衡** 多节点部署时使用round_robin策略: ```cpp args.SetLoadBalancingPolicyName("round_robin"); ``` #### 四、调试与监控 1. **日志跟踪** 启用gRPC详细日志: ```cpp setenv("GRPC_VERBOSITY", "DEBUG", 1); ``` 2. **健康检查** 实现健康检查接口: ```protobuf service Health { rpc Check(HealthRequest) returns (HealthResponse); } ``` > **注意**:生产环境需启用TLS加密,使用`grpc::SslServerCredentials()`替代`InsecureServerCredentials()`[^1][^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值