grpc-通关速成

一、前言

1、什么是grpc, 设计该通信协议的背景、目的、可以用来做什么?

grpc全称:"Google Remote Procedure Call", 谷歌远程过程调用;

背景:原来在开发架构中很多采用"单体架构",将所有的功能模块集成到一个exe程序,但是当针对某个模块功能进行升级时,需要将整个程序进行升级;且当程序中某个模块宕机了,会导致整个软件的宕机;且当某个功能需要增加资源开支时,是对整个软件资源的开支增加,整体按照功能模块的伸缩性差;代码直接的耦合性高;

目的:为了解决模块间解耦,加强功能模块的伸缩性,这里引入了"微服务"架构;

微服务架构,采用grpc通信的方式进行,功能服务之间的解耦,服务之间是进程之间的关系

grpc远程调用屏蔽计算机底层调用细节以及编程语言之间的差异。跟本地调用一个函数一样,底层的通信实现交给了grpc处理

2、grpc协议的特点?以及优缺点?

grpc,数据是二进制字节流,采用了约定的编码,这里使用的是protobuff,因此安全性高

跨平台,跨语言,接口即代码

grpc支持多种通信模式,支持一对一,多对一,一对多,或多对多,支持断点续传;

缺点:

(1)、可读性差;

(2)、数据结构更改需要重新编译;

(3)、学习成本高;

二、编译安装(C++)

本文中提供编译好的库文件,编译好的环境是基于(msvc 2019 + 64位

1、编译源码

1.1、下载源码以及第三方库依赖

这里下载1.34版本的grpc, 这里使用国内镜像源仓库下载:(如果网络条件好,可以从github上下载)也可以从下面网盘地址获取

通过网盘分享的文件:grpc.zip

链接: https://pan.baidu.com/s/1__auslBbTnmbL99EEI16_w 提取码: 8888

cpp 复制代码
 git clone -b v1.34.0 https://gitee.com/mirrors/grpc-framework.git grpc_1.34

查看下载后的仓库所在文件夹:

cpp 复制代码
[submodule "third_party/zlib"]
	path = third_party/zlib
	url = https://gitee.com/mirrors/zlib.git
	# When using CMake to build, the zlib submodule ends up with a
	# generated file that makes Git consider the submodule dirty. This
	# state can be ignored for day-to-day development on gRPC.
	ignore = dirty
[submodule "third_party/protobuf"]
	path = third_party/protobuf
	url = https://gitee.com/local-grpc/protobuf.git
[submodule "third_party/googletest"]
	path = third_party/googletest
	url = https://gitee.com/local-grpc/googletest.git
[submodule "third_party/benchmark"]
	path = third_party/benchmark
	url = https://gitee.com/mirrors/google-benchmark.git
[submodule "third_party/boringssl-with-bazel"]
	path = third_party/boringssl-with-bazel
	url = https://gitee.com/mirrors/boringssl.git
[submodule "third_party/re2"]
	path = third_party/re2
	url = https://gitee.com/local-grpc/re2.git
[submodule "third_party/cares/cares"]
	path = third_party/cares/cares
	url = https://gitee.com/mirrors/c-ares.git
	branch = cares-1_12_0
[submodule "third_party/bloaty"]
	path = third_party/bloaty
	url = https://gitee.com/local-grpc/bloaty.git
[submodule "third_party/abseil-cpp"]
	path = third_party/abseil-cpp
	url = https://gitee.com/mirrors/abseil-cpp.git
	branch = lts_2020_02_25
[submodule "third_party/envoy-api"]
	path = third_party/envoy-api
	url = https://gitee.com/local-grpc/data-plane-api.git
[submodule "third_party/googleapis"]
	path = third_party/googleapis
	url = https://gitee.com/mirrors/googleapis.git
[submodule "third_party/protoc-gen-validate"]
	path = third_party/protoc-gen-validate
	url = https://gitee.com/local-grpc/protoc-gen-validate.git

拉取第三方依赖:

bash 复制代码
git submodule update --init

1.2 grpc这边需要汇编编译器,这里从下面链接下载:

bash 复制代码
https://www.nasm.us/pub/nasm/releasebuilds/2.16.03/win64/ 

下载解压完,将路径放到环境变量中:

1.3、下载安装好cmake

创建编译目录,跟安装文件夹如下:

1.4、构建项目

cmake构建时,必须保证自己已经安装了相关的编译工具链,我已经安装了Vs Msvc2017的工具链;

构建选择有如下修改:

所有与测试相关的属性都不要勾选

我这里只使用C++跟Python版本的插件,所以下面选择这两个:

grpc依赖protobuf,所以这里需要选择protobuf的依赖跟生成器:

构建过程中的警告可以忽略,但是ERROR一定要解决!

1.5、编译

2、部署导出

用管理员方式打开CMD

进入到编译目录下grpc_build\

bash 复制代码
cmake --install .  --config Debug    # 导出debug版本
cmake --install .  --config Release    # 导出Release版本

三、使用教程

进行grpc通信之前先定义好通信服务的接口,例如下文举例:

msg.proto

bash 复制代码
syntax = "proto3";

// 消息包名,类似于C++中的名字空间
package demo;

// 求和请求
message addRequest{
    int32 paramA = 1;   // 1 表示第一个参数
    int32 paramB = 2;   // 2 表示第二个参数
}

// 求和答复
message addResReply{
    bool res = 1;
    int32 sum = 2;
}

// 服务定义(用于 RPC 框架,如 gRPC,定义接口方法)
service demoService{
    // 两数求和
    rpc GetTwoParamSum(addRequest) returns(addResReply);
}

根据msg.proto文件生成对应使用到的头文件跟源文件

bash 复制代码
 ./protoc.exe -I . --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc="grpc_cpp_plugin.exe" msg.proto

下面列举一个服务端,客户端的使用的实例:

服务端:

demo_server.h

bash 复制代码
#ifndef _DEMO_SERVER_H
#define _DEMO_SERVER_H

#include <iostream>
#include <cstdio>
#include <grpcpp/grpcpp.h>
#include "msg.grpc.pb.h"

class Demo_Server: public demo::demoService::Service
{
public:
    explicit Demo_Server();
    ~Demo_Server() override;

    // 实现远程调用接口
    virtual grpc::Status GetTwoParamSum(grpc::ServerContext* context, 
        const demo::addRequest* request, demo::addResReply* response) override;
};

#endif

demo_server.cpp

cpp 复制代码
# include "demo_server.h"

Demo_Server::Demo_Server(){

}

Demo_Server::~Demo_Server(){

}

/*
   参数:
    context: 上下文远程调用的额外信息
    request: 客户端传递数据参数
    response: 返回值
*/
grpc::Status Demo_Server::GetTwoParamSum(grpc::ServerContext* context, 
                                         const demo::addRequest* request, demo::addResReply* response) 
{
    int inParamA = request->parama();
    int inParamB = request->paramb();
    int iOutRes = inParamA + inParamB;
    response->set_res(true);
    response->set_sum(iOutRes);
    return grpc::Status::OK;
}

main.cpp

cpp 复制代码
#include <stdio.h>
#include <iostream>
#include <grpcpp/grpcpp.h>
#include "demo_server.h"

std::unique_ptr<grpc::Server> gServer;
// 设置服务参数,启动服务器
bool runServer(std::shared_ptr<Demo_Server> pService){
    grpc::ServerBuilder builder;
    builder.AddListeningPort("0.0.0.0:50052", grpc::InsecureServerCredentials()); // 第二个参数表示不安全连接
    builder.RegisterService(pService.get());
    gServer = builder.BuildAndStart();
    gServer->Wait();
    return true;
}

int main(){
    std::shared_ptr<Demo_Server> pServer = std::make_shared<Demo_Server>();
    runServer(pServer);
    return 0;
}

客户端:

bash 复制代码
#include <iostream>
#include <cstdio>
#include <grpcpp/grpcpp.h>
#include "msg.grpc.pb.h"

using namespace demo;

void runClient(){
    // 构建连接通道
    std::shared_ptr<grpc::Channel> channel = grpc::CreateChannel("127.0.0.1:50052", grpc::InsecureChannelCredentials());
    // 创建远程调用代理
    std::unique_ptr<demoService::Stub> pStub = demoService::NewStub(channel);
    // 通过代理远程调用服务端程序
    grpc::ClientContext comtext;
    addRequest addReq;
    addReq.set_parama(20);
    addReq.set_paramb(35);

    addResReply addRep;
    addRep.set_res(false);
    grpc::Status resState = pStub->GetTwoParamSum(&comtext, addReq, &addRep);

    if(resState.ok())
    {
        std::cout << "add result:" << addRep.sum() << std::endl;
    }
    else{
        std::cerr << "exec GetTwoParamSum error:" <<resState.error_code() << "" <<resState.error_message() << std::endl; 
    }
}

int main(){
    runClient();
    return 0;
}

运行效果:

资源链接:

grpc1.35编译好的window+msvc环境下的库,包含debug/release版本,提供使用实例资源-CSDN下载https://download.csdn.net/download/weixin_36323170/92626411?spm=1001.2014.3001.5503

相关推荐
ShineWinsu4 小时前
对于C++:继承的解析—上
开发语言·数据结构·c++·算法·面试·笔试·继承
小付同学呀5 小时前
C语言学习(五)——输入/输出
c语言·开发语言·学习
梦幻精灵_cq5 小时前
学C之路:不可或缺的main()主函数框架(Learn-C 1st)
c语言·开发语言
消失的旧时光-19435 小时前
C++ 多线程与并发系统取向(二)—— 资源保护:std::mutex 与 RAII(类比 Java synchronized)
java·开发语言·c++·并发
福大大架构师每日一题6 小时前
go-zero v1.10.0发布!全面支持Go 1.23、MCP SDK迁移、性能与稳定性双提升
开发语言·后端·golang
抓饼先生7 小时前
iceoryx编译和验证
linux·c++·零拷贝·iceoryx
王老师青少年编程7 小时前
2020年信奥赛C++提高组csp-s初赛真题及答案解析(阅读程序第2题)
c++·题解·真题·初赛·信奥赛·csp-s·提高组
五阿哥永琪7 小时前
1. 为什么java不能用is开头来做布尔值的参数名,会出现反序列化异常。
java·开发语言
逻极8 小时前
pytest 入门指南:Python 测试框架从零到一(2025 实战版)
开发语言·python·pytest
你的冰西瓜8 小时前
C++ STL算法——排序和相关操作
开发语言·c++·算法·stl