Введение в gRPC для C++
gRPC — это современный фреймворк для удалённого вызова процедур (RPC), разработанный Google. Он использует Protocol Buffers (protobuf) для сериализации данных и HTTP/2 в качестве транспортного протокола. Для языка C++ gRPC предоставляет нативные библиотеки, позволяющие создавать высокопроизводительные микросервисы и распределённые системы.
В этой статье мы разберём основные библиотеки, настройку окружения и напишем полноценный пример клиент-серверного приложения на C++.
Основные библиотеки gRPC для C++
Для работы с gRPC в C++ требуется установить несколько компонентов:
- grpc — основная библиотека, содержащая реализации сервера и клиента.
- grpc++ — C++-обёртка над gRPC, предоставляющая удобный API.
- protobuf — библиотека для работы с Protocol Buffers (генерация классов, сериализация/десериализация).
- grpc_cpp_plugin — плагин для компилятора protoc, который генерирует C++-код из .proto файлов.
Также могут потребоваться зависимости: abseil-cpp, openssl, zlib и c-ares.
Установка gRPC и protobuf
Рекомендуемый способ — сборка из исходников через CMake. Пример для Linux/macOS:
git clone --recurse-submodules -b v1.60.0 https://github.com/grpc/grpc
cd grpc
mkdir build && cd build
cmake .. -DgRPC_INSTALL=ON -DCMAKE_INSTALL_PREFIX=/usr/local
make -j$(nproc)
sudo make install
После установки проверьте доступность компилятора protobuf и плагина:
protoc --version
which grpc_cpp_plugin
Определение сервиса через .proto файл
Создадим файл example.proto:
syntax = "proto3";
package example;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
Сгенерируем C++-код:
protoc --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` example.proto
В результате появятся файлы: example.pb.h, example.pb.cc, example.grpc.pb.h, example.grpc.pb.cc.
Реализация сервера на C++
Создайте файл server.cc:
#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#include "example.grpc.pb.h"
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using example::Greeter;
using example::HelloRequest;
using example::HelloReply;
class GreeterServiceImpl final : public Greeter::Service {
Status SayHello(ServerContext* context,
const HelloRequest* request,
HelloReply* reply) override {
std::string prefix("Hello, ");
reply->set_message(prefix + request->name());
return Status::OK;
}
};
void RunServer() {
std::string server_address("0.0.0.0:50051");
GreeterServiceImpl 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() {
RunServer();
return 0;
}
Реализация клиента на C++
Создайте файл client.cc:
#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#include "example.grpc.pb.h"
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using example::Greeter;
using example::HelloRequest;
using example::HelloReply;
class GreeterClient {
public:
GreeterClient(std::shared_ptr<Channel> channel)
: stub_(Greeter::NewStub(channel)) {}
std::string SayHello(const std::string& user) {
HelloRequest request;
request.set_name(user);
HelloReply reply;
ClientContext context;
Status status = stub_->SayHello(&context, request, &reply);
if (status.ok()) {
return reply.message();
} else {
std::cerr << "RPC failed: