Ответ
gRPC — это высокопроизводительный фреймворк удаленного вызова процедур (RPC) с открытым исходным кодом, изначально разработанный в Google. Он основан на HTTP/2 и использует Protocol Buffers (protobuf) в качестве языка описания интерфейсов (IDL) и формата сериализации.
Ключевые преимущества для C++ разработки:
- Производительность: Бинарный протокол protobuf и мультиплексирование потоков в HTTP/2 обеспечивают низкую задержку и высокую пропускную способность.
- Строгая типизация: Интерфейсы и структуры данных определяются в
.proto-файлах, что исключает ошибки несоответствия типов между клиентом и сервером. - Поддержка потоковой передачи: Помимо простых запросов-ответов, поддерживаются однонаправленные и двунаправленные потоки.
Пример: простой сервис на C++
-
Определение сервиса (
greeter.proto):syntax = "proto3"; package helloworld; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; } -
Реализация сервера (упрощенно):
#include <grpcpp/grpcpp.h> #include "greeter.grpc.pb.h" class GreeterServiceImpl final : public helloworld::Greeter::Service { grpc::Status SayHello(grpc::ServerContext* context, const helloworld::HelloRequest* request, helloworld::HelloReply* reply) override { std::string prefix("Hello, "); reply->set_message(prefix + request->name()); return grpc::Status::OK; } }; void RunServer() { std::string server_address("0.0.0.0:50051"); GreeterServiceImpl service; grpc::ServerBuilder builder; builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); builder.RegisterService(&service); std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); server->Wait(); } -
Клиентский вызов (упрощенно):
auto channel = grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()); std::unique_ptr<helloworld::Greeter::Stub> stub = helloworld::Greeter::NewStub(channel); helloworld::HelloRequest request; request.set_name("World"); helloworld::HelloReply reply; grpc::ClientContext context; grpc::Status status = stub->SayHello(&context, request, &reply); if (status.ok()) { std::cout << reply.message() << std::endl; }
Типичное применение: микросервисные архитектуры, межпроцессное взаимодействие (IPC), клиент-серверные приложения, где важны низкая задержка и эффективность.
Ответ 18+ 🔞
А, gRPC! Ну это, блядь, такая штука, чтобы сервисы между собой болтали, как будто они в одном процессе сидят, а на самом деле — по сети, через всю эту интернет-хуйню. Google её придумал, там умные дядьки, ёпта. Главный козырь — скорость, просто овердохуища быстрая, потому что под капотом у неё HTTP/2 и бинарные протоколы буферов, а не эта ваша JSON-писанина, которая весит, как хуй с горы.
Чем она для C++ плюшевая:
- Скорость пиздец: Всё бинарное, сжатое, да ещё и несколько запросов в одном соединении гонять можно. Не то что эти REST'ы, которые для каждой ерунды новое соединение открывают — терпения ноль ебать.
- Контракты железные: Ты сперва в
.proto-файле описываешь, какие методы будут и какие структуры данных летать. Потом компилятор тебе нагенерит код, и всё — никаких «ой, а я думал, полеuserNameназывается, а неusername». Доверия ебать ноль к ручному парсингу, зато тут — строгая типизация, красота. - Не только туда-сюда: Можно не просто запрос-ответ, а целые потоки данных в одну сторону или даже в обе сразу гнать. Очень удобно, когда надо, например, чат сделать или лог-стрим пулять.
Смотри, как это примерно выглядит, на пальцах:
-
Пишем контракт (
greeter.proto): Тут всё просто, как три копейки. Объявляем сервисGreeterс одним методомSayHello. Он принимает сообщениеHelloRequestс именем и отдаётHelloReplyс приветствием. Э бошка думай — логика же элементарная.syntax = "proto3"; package helloworld; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; } -
Делаем сервер (вот, смотри код): Берём сгенерированный класс, наследуемся, переопределяем метод. Пришёл запрос — достаём имя, лепим к нему «Hello, » и отправляем назад. В рот меня чих-пых, да тут и думать нечего.
#include <grpcpp/grpcpp.h> #include "greeter.grpc.pb.h" class GreeterServiceImpl final : public helloworld::Greeter::Service { grpc::Status SayHello(grpc::ServerContext* context, const helloworld::HelloRequest* request, helloworld::HelloReply* reply) override { std::string prefix("Hello, "); reply->set_message(prefix + request->name()); return grpc::Status::OK; } }; void RunServer() { std::string server_address("0.0.0.0:50051"); GreeterServiceImpl service; grpc::ServerBuilder builder; builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); builder.RegisterService(&service); std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); server->Wait(); } -
Клиент, который дергает сервер: Создаём канал к серверу, делаем «стаб» (это такая заглушка-клиент), набиваем запрос данными и просто вызываем метод, как будто он локальный! Ни хуя себе, правда? А вся сетевая магия происходит под капотом.
auto channel = grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()); std::unique_ptr<helloworld::Greeter::Stub> stub = helloworld::Greeter::NewStub(channel); helloworld::HelloRequest request; request.set_name("World"); helloworld::HelloReply reply; grpc::ClientContext context; grpc::Status status = stub->SayHello(&context, request, &reply); if (status.ok()) { std::cout << reply.message() << std::endl; }
Где эту радость применяют? Да везде, где сервисы друг другу не дают покоя. Микросервисы, которые общаются чаще, чем соседки у подъезда, всякие высоконагруженные штуки, где каждая миллисекунда на счету, или даже просто замена своему корявому IPC. В общем, ебать мои старые костыли, хорошая технология.
Видео-ответы
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶