c++实现gRPC

news/2024/11/7 10:46:20/

        无论什么语言,实现grpc的核心是.proto文件,通过protoc命令将.proto文件生成grpc框架的接口文件*gb*, 该文件中包含.proto定义的方法及参数接口,服务器,客户端相关操作接口;然后再编写服务器,客户端代码,调用*gb*文件生成的接口。

        直接实例代码介绍其过程:

        核心文件:hello.proto

syntax = "proto3"; // 规定使用proto3的语法
service MsgService { // 定义服务, 流数据放到括号里面rpc GetMsg (MsgRequest) returns (MsgResponse){}
}message MsgRequest { // 请求的结构, 也可以定义int32,int64,double,float等数据类型, 等号后面的数字表示第几个string name = 1;
}message MsgResponse { // 回应的结果string msg = 1;
}

        然后执行:

protoc -I . --cpp_out=. ./hello.proto#生成hello.pb.cc文件protoc -I . --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` ./hello.proto#生成hello.grpc.pb.cc文件
或者
protoc -I . --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` ./hello.proto#一起生成两个文件-I :(-IPATH)指定要在其中搜索导入(import)的目录。可指定多次,目录将按顺序搜索。如果没有给出,则使用当前工作目录。
--cpp_out = . : 以c++语言格式输出,等号后面为输出文件存放的路径
--grpc_out = . :输出grpc框架接口文件。等号后面为输出文件存放的路径
--plugin=`which grpc_cpp_plugin` :指定一个protobuf插件(grpc_cpp_plugin)来生成grpc代码。hello.proto : 核心文件,可以是路径./hello.proto,或者绝对路径。

        执行成功后,指定的目录下会生成两个文件:

        hello_pb.cc/hello_pb.h:主要是对参数(MsgRequest,MsgResponse)的属性设置,参数类的重定向,参数成员的设置,获取等操作。

        hello_pb_grpc.cc/hello_grpc_pb.h :该文件生成了proto方法(GetMsg)的属性操作接口,通过该存根实现服务器与客户端的通讯

        生成这两个文件之后就可以编写服务器,客户端代码了:

        服务器代码(hello_server.cc):

#include <iostream>
#include <memory>
#include <string>#include <grpcpp/grpcpp.h>#include "hello.grpc.pb.h"
#include "hello.pb.h"using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;//创建类,继承MsgService::Service, 父类在生成的hello.grpc.pb.cc/h文件中,属于grpc的服务端接口类
class MyServer final : public MsgService::Service{Status GetMsg(ServerContext* context, const MsgRequest* request, MsgResponse* reply) override{//hello.grpc.pb文件生成的类接口std::string str("Hello ");reply->set_msg( str + request->name());//hello.pb文件生成的类接口,设置回复结构的成员数据return Status::OK;}
};void RunServer(){std::string server_address("0.0.0.0:50051");MyServer service;ServerBuilder builder;builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());builder.RegisterService(&service);std::unique_ptr<Server> server(builder.BuildAndStart());std::cout << "server listen on ..." << server_address << std::endl;server->Wait();
}int main(int argc, char **argv)
{RunServer();return 0;
}

客户端:

#include <iostream>
#include <memory>
#include <string>#include <grpcpp/grpcpp.h> // 和python一样, import grp// 在包含两个信息和应用的头文件
#include "hello.grpc.pb.h"
#include "hello.pb.h"// 这是通用工具
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;class MsgServiceClient {public:MsgServiceClient(std::shared_ptr<Channel> channel): stub_(MsgService::NewStub(channel)) {}MsgResponse GetMsg(const std::string& user, int num1, double num2) {// 请求数据数据格式化到requestMsgRequest request; request.set_name(user);request.set_num1(num1);request.set_num2(num2);// 服务器返回端MsgResponse reply;//客户端上下文。它可以用来传递额外的信息//服务器和/或调整某些RPC行为。ClientContext context;// The actual RPC.Status status = stub_->GetMsg(&context, request, &reply);if (status.ok()) {return reply;} else {std::cout << status.error_code() << ": " << status.error_message()<< std::endl;return reply;}}private:std::unique_ptr<MsgService::Stub> stub_;
};int main(int argc, char** argv) {MsgServiceClient z_msg(grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()));std::string user("world");MsgResponse reply = z_msg.GetMsg(user);std::cout<<reply.msg()<<std::endl;printf("num1 = %d;  num2=%f\n", reply.num1(), reply.num2());return 0;
}

        cmake编译:

        CMakeLists.txt编写:

cmake_minimum_required(VERSION 3.5)
project(test2)include(/XXX/gRPC/grpc/examples/cpp/cmake/common.cmake)#调用grpc环境配置,该路径为绝对路径set(PWDIR ${CMAKE_CURRENT_SOURCE_DIR})
set(GRPCDIR "/XXX/gRPC/grpc/cmake/build/_install")#编译grpc时指定的安装路径include_directories(${PWDIR}${GRPCDIR}/include
)link_directories(${GRPCDIR}/lib
)add_library(hw_grpc_proto"${PWDIR}/hello.grpc.pb.cc""${PWDIR}/hello.pb.cc"
)
target_link_libraries(hw_grpc_proto protobuf protobuf-lite protoc grpc++_reflection gRPC::grpc++)foreach(_targethello_server hello_client)add_executable(${_target} "${_target}.cpp")target_link_libraries(${_target}hw_grpc_proto)
endforeach()

        后期会发布一篇grpc程序编写的完整流程,从proto,*.pb.cc, *.grpc.pb.cc解析 到服务器 客户端代码编写,cmake编写,返回状态设置,.cmake文件解析, rpc流式传输 的全面刨析,让您一篇文章学会grpc。

        感兴趣的话关注。一起交流学习。


http://www.ppmy.cn/news/74451.html

相关文章

3-《安卓基础》

3-《安卓基础》 一.Android系统架构二.四大组件1. Activity1.1 生命周期1.2. Activity四种启动模式1.3.Activity任务栈的概念1.4 面试题面试题1&#xff1a;onSaveInstanceState(Bundle outState)&#xff0c;onRestoreInstanceState(Bundle savedInstanceState) 的调用时机&am…

springboot+swagger项目中,controller引入@NotEmpty等校验注解的问题

springboot项目 springbootswagger项目中&#xff0c;controller层如果使用对基本数据类型使用 NotEmpty Length 等校验注解&#xff0c;controller会获取不到值&#xff0c;加了RequestBody后可以获取到了&#xff0c;但是前端传值content-type必须是text/plain。所以建议con…

力扣sql中等篇练习(二十六)

力扣sql中等篇练习(二十六) 1 世界排名的变化 1.1 题目内容 1.1.1 基本题目信息1 1.1.2 基本题目信息2 1.1.3 示例输入输出 a 示例输入 b 示例输出 1.2 示例sql语句 # 分别求出变化前后的排名 然后再进行内连接即可 # row_number()里面也可以用多个字段加减的表达式去进行…

动态ip与静态ip的区别是什么?

动态ip和静态ip的区别在于&#xff1a; 动态ip可以自动获取IP地址&#xff0c;静态ip需要手动设置IP地址。 动态ip一般用于局域网内部或小型企业网中&#xff0c;静态ip一般用于大型企业网或骨干网等对安全性要求高的场合。 在网速上&#xff0c;动态ip和静态ip没有区别。 动…

文心一言和ChatGPT最全对比

文心一言和ChatGPT都是基于深度学习技术的自然语言处理模型&#xff0c;有各自的优势和使用场景&#xff0c;无法简单地比较 ChatGPT 和文心一言哪一个功能更强大&#xff0c;它们各自具有优势和局限性&#xff0c;需要根据具体需求进行选择&#xff0c;以下一些具体对比&#…

生成式AI热潮:一场“添饭碗”的科技革命

今年以来&#xff0c;人工智能&#xff08;AI&#xff09;热潮席卷全球&#xff0c;被认为将掀起新的科技革命。 5月18日的2023天津世界智能大会&#xff0c;以“智行天下 能动未来”为主题&#xff0c;重点关注人工智能发展的新趋势、新技术、新业态。大会开幕式结束之后&…

【观察】共建“伙伴+华为”背后,是华为平台到体系的战略“升维”

2017年&#xff0c;在当年的“伙伴大会”上&#xff0c;华为首次提出以“平台生态”双轮驱动的战略&#xff0c;以更加开放的心态积极拥抱产业变化&#xff0c;通过和产业链上各个层级的合作伙伴一起合作&#xff0c;共同实现新的市场突破。 彼时中国企业和行业的数字化转型刚刚…

本地搭建wamp服务器并内网穿透实现无公网IP远程访问

文章目录 前言1.Wamp服务器搭建1.1 Wamp下载和安装1.2 Wamp网页测试 2. Cpolar内网穿透的安装和注册2.1 本地网页发布2.2 Cpolar云端设置2.3 Cpolar本地设置 3. 公网访问测试4. 结语 转载自cpolar极点云的文章&#xff1a;无公网IP&#xff1f;教你在外远程访问本地Wamp服务器「…