Bootstrap

什么是gRPC?

gRPC(gRPC Remote Procedure Call)是一个高性能、开源、通用的远程过程调用(RPC)框架,最初由 Google 开发。gRPC 使用 HTTP/2 作为传输协议,并采用 Protocol Buffers(protobuf)作为接口描述语言(IDL)和数据序列化协议。

gRPC 的主要特点

  1. 高性能和高效:

    • gRPC 利用 HTTP/2 提供高效的二进制传输,流式传输,多路复用,以及优先级和头部压缩等功能。
    • 通过 Protocol Buffers 进行高效的序列化和反序列化,确保数据在传输过程中的紧凑性和速度。
  2. 多语言支持:

    • gRPC 支持多种编程语言,包括但不限于 C++, Java, Python, Go, Ruby, C#, Node.js 和 PHP。这样不同语言的服务可以方便地互相调用。
  3. 自动代码生成:

    • gRPC 使用 Protocol Buffers 描述服务接口和消息结构,通过工具链自动生成客户端和服务端的代码,这减少了手动编写重复代码的需要。
  4. 双向流式通信:

    • gRPC 支持双向流式通信,允许客户端和服务端之间进行实时数据交换,适用于需要实时通信的应用场景。
  5. 互操作性和扩展性:

    • gRPC 可以方便地在多种环境中部署,包括云计算环境、数据中心、移动设备等,并能与其他系统进行互操作。

典型应用场景

  • 微服务架构:
    gRPC 非常适合微服务架构中各个服务之间的高效通信。
  • 实时通信:
    适用于需要实时数据交换的应用,如视频流、实时聊天等。
  • 跨语言通信:
    在多语言环境中,gRPC 提供了统一的接口和高效的通信机制。

资源

以下是使用C++实现一个简单的gRPC示例。这个示例同样是一个简单的计算器服务,提供加法运算。

1. 定义服务 (Proto文件)

首先,创建一个Proto文件(calculator.proto),定义服务和消息类型。

syntax = "proto3";

package calculator;

// 定义请求消息
message AddRequest {
  int32 a = 1;
  int32 b = 2;
}

// 定义响应消息
message AddResponse {
  int32 result = 1;
}

// 定义计算器服务
service Calculator {
  rpc Add(AddRequest) returns (AddResponse);
}

2. 生成代码

使用 protoc 工具生成C++代码。确保你已经安装了gRPC和Protobuf工具。运行以下命令生成代码:

protoc --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` calculator.proto

这将生成 calculator.pb.h, calculator.pb.cc, calculator.grpc.pb.hcalculator.grpc.pb.cc 文件。

3. 实现服务器端

创建一个C++文件(server.cpp),实现服务器端代码。

#include <iostream>
#include <memory>
#include <string>

#include <grpcpp/grpcpp.h>
#include "calculator.grpc.pb.h"

using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using calculator::AddRequest;
using calculator::AddResponse;
using calculator::Calculator;

// 实现服务定义
class CalculatorServiceImpl final : public Calculator::Service {
public:
    Status Add(ServerContext* context, const AddRequest* request, AddResponse* response) override {
        int a = request->a();
        int b = request->b();
        response->set_result(a + b);
        return Status::OK;
    }
};

// 启动gRPC服务器
void RunServer() {
    std::string server_address("0.0.0.0:50051");
    CalculatorServiceImpl service;

    ServerBuilder builder;
    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
    builder.RegisterService(&service);

    std::unique_ptr<Server> server(builder.BuildAndStart());
    std::cout << "Server listening on " << server_address << std::endl;
    server->Wait();
}

int main(int argc, char** argv) {
    RunServer();
    return 0;
}

4. 实现客户端

创建另一个C++文件(client.cpp),实现客户端代码。

#include <iostream>
#include <memory>
#include <string>

#include <grpcpp/grpcpp.h>
#include "calculator.grpc.pb.h"

using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using calculator::AddRequest;
using calculator::AddResponse;
using calculator::Calculator;

class CalculatorClient {
public:
    CalculatorClient(std::shared_ptr<Channel> channel)
        : stub_(Calculator::NewStub(channel)) {}

    int Add(int a, int b) {
        AddRequest request;
        request.set_a(a);
        request.set_b(b);

        AddResponse response;
        ClientContext context;

        Status status = stub_->Add(&context, request, &response);

        if (status.ok()) {
            return response.result();
        } else {
            std::cerr << "RPC failed" << std::endl;
            return -1;
        }
    }

private:
    std::unique_ptr<Calculator::Stub> stub_;
};

int main(int argc, char** argv) {
    CalculatorClient client(grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()));
    int result = client.Add(10, 20);
    std::cout << "Add result: " << result << std::endl;

    return 0;
}

5. 编译和运行

确保你已经安装了gRPC和Protobuf的开发库。可以使用以下命令编译和运行服务器和客户端。

编译
g++ -std=c++11 server.cpp calculator.pb.cc calculator.grpc.pb.cc -o server -lgrpc++ -lprotobuf -lpthread
g++ -std=c++11 client.cpp calculator.pb.cc calculator.grpc.pb.cc -o client -lgrpc++ -lprotobuf -lpthread
运行

首先运行服务器:

./server

然后在另一个终端窗口运行客户端:

./client

你应该会看到客户端输出:

Add result: 30

解释

  1. Proto文件:定义了服务和消息类型。
  2. 服务器端:实现了Calculator服务,并启动了gRPC服务器监听特定端口。
  3. 客户端:创建了一个gRPC通道,调用了远程的Add方法,并获取了结果。
;