gRPC系列(一) 安装和入门

gRPC系列(一) 安装和入门

gRPC是由谷歌公司开发的一款rpc框架,支持多种语言,包括C++、Java、Golang、python等等。这个系列将会主要记录gRPC的学习过程,本文主要包括安装和简单的使用,语言为C++。

安装

我的操作系统是ubuntu20.04。

  1. 安装依赖

    sudo apt-get install pkg-config
    sudo apt-get install autoconf automake libtool make g++ unzip
    sudo apt-get install libgfalgs-dev libgtest-dev
    sudo apt-get install clang libc++-dev
  2. 下载gRPC

    git clone https://github.com/grpc/grpc.git
    cd grpc
    git submodule update --init // 更新第三方源码
  3. 安装protobuf源码

    cd third_party/protobuf/
    git submodule update --init --recursive
    ./autogen.sh // 生成配置脚本
    ./configure  // 生成Makefile文件,为下一步的编译做准备,可以加上安装路径:--prefix=path
    make
    make check
    sudo make install
    sudo ldconfig    // 更新共享库缓存
    which protoc    // 查看软件是否安装成功
    protoc --version // 检查是否安装成功
  4. 安装gRPC

    cd ../..
    make
    sudo make install

简单使用

使用grpc包括几个步骤:定义服务、生成代码、编写服务端代码、编写客户端代码、运行。

定义服务

服务定义文件是proto文件,中文文档可以参考Protobuf语法指南
这里先写一个简单的proto文件

syntax="proto3";
// 语法类型
package Simple;
// 这是生成代码使用的namespace,所有生成的代码都会在这个namespace中。

// 指定服务的名称,生成的代码里面的二级namespace
service Server {
    rpc Echo(EchoRequest) returns (EchoReponse){}
}

message EchoRequest {
    string msg = 1;    // 
}

message EchoResponse {
    string msg = 1;
}

上面的接口中,必须有参数和返回值,如果不需要参数或者返回值,也必须定义一个空的(没有成员)message,否则无法通过编译。

生成代码

安装好grpc之后,可以使用grpc的相关的命令行程序,来使用proto文件生成C++代码,这里需要分两步走,一个是生成protobuf序列化和反序列化代码,二是生成基本服务框架代码。

> protoc -I ./ --cpp_out=. simple.proto
> protoc -I ./ --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` simple.proto
> ls
simple.grpc.pb.cc  simple.grpc.pb.h  simple.pb.cc  simple.pb.h  simple.proto

编写服务端代码

服务端我们需要继承生成文件simple.grpc.pb.h中的Simple::Server::Service,实现上述定义的rpc接口,我们可以看一下simple.grpc.pb.h文件中的内容。
image.png
简单的服务端代码如下:

#include 

#include 
#include 

#include "../protos/simple/simple.grpc.pb.h"
// 添加自己的路径

using grpc::Status;
using grpc::ServerContext;


class SimpleServiceImpl final : public Simple::Server::Service{
    public:
        Status Echo(ServerContext* context,
                const Simple::EchoRequest* req,
                Simple::EchoResponse* resp)override
        {
            resp->set_msg(req->msg());
            return Status::OK;
        }
};

int main()
{
    // 服务器构建器
    grpc::ServerBuilder builder;
    // 添加监听的地址和端口,选择不认证
    builder.AddListeningPort("localhost:12345",grpc::InsecureServerCredentials());
    // 注册服务
    ServiceImpl service;
    builder.RegisterService(&service);
    // 构建服务器
    std::unique_ptr server(builder.BuildAndStart());
    std::cout << "Server running" << std::endl;
    // 进入服务器处理循环
    server->Wait();
    return 0;
}

然后运行我们的程序(不要忘记链接grpc库和源文件simple.grpc.pb.cc、simple.pb.cc)。
我是用CMake构建编译链的,在项目目录的CMakeLists.txt中查找库并添加到路径中。

set(protobuf_MODULE_COMPATIBLE True)
find_package(Protobuf REQUIRED)
set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)

# set grpc
find_package( gRPC REQUIRED)
set(_GRPC_GRPCPP_UNSECURE gRPC::grpc++_unsecure)

include_directories(
    ${_PROTOBUF_INCLUDE_DIR}
    ${PROJECT_SOURCE_DIR}/grpc/protos
)

在simple.cpp所在路径添加依赖

add_executable(SimpleClient simple_client.cpp)

target_link_libraries(SimpleClient
    ${_GRPC_GRPCPP_UNSECURE}
    ${_PROTOBUF_LIBPROTOBUF}
    simple.grpc.pb.cc
    simple.pb.cc
    )

add_executable(SimpleServer simple_server.cpp)

target_link_libraries(SimpleServer
    ${_GRPC_GRPCPP_UNSECURE}
    ${_PROTOBUF_LIBPROTOBUF}
    simple.grpc.pb.cc
    simple.pb.cc
    )

install(TARGETS
    SimpleServer
    SimpleClient
    DESTINATION bin/
    )

然后编译过程如下:

// 进入项目根目录下,
> mkdir -p build
> cd build
> cmake ../ CMAKE_INSTALL_PREFIX="your_install_path"
> cd your_install_path/bin
> ./SimpleServer
> Server running

编写客户端代码

#include 
#include 

#include 
#include 
#include 
#include 
#include 

#include "../protos/simple/simple.grpc.pb.h"

using grpc::Status;
using grpc::Channel;
using grpc::ClientContext;

int main()
{
    // 创建一个channel,维护的是和服务器的连接
    std::shared_ptr chan = grpc::CreateChannel("localhost:12345",grpc::InsecureChannelCredentials());
    // 创建一个stub
    std::unique_ptr stub = Simple::Server::NewStub(chan);

    Simple::EchoRequest req;
    req.set_msg("Hello World");
    Simple::EchoResponse resp;
    ClientContext context;
    Status st = stub->Echo(&context,req,&resp);
    if(st.ok()){
        std::cout << resp.msg() <

编译和上面服务器编译方法一致:

> SimpleClient
Hello World
> 

你可能感兴趣的