RPC讲解与完整版C++代码示例

1. RPC 是什么?

RPC(Remote Procedure Call,远程过程调用)是一种技术,允许计算机程序调用另一台机器(服务器)上的程序或服务,而看起来就像是本地过程调用一样。RPC 抽象了底层的网络通信过程,使得开发者可以不用详细处理网络交互的细节,直接进行函数或方法的调用。

2. 为什么要用 RPC?

  • 分布式系统开发简化:RPC 允许开发者在构建分布式系统时,像调用本地对象一样调用远程服务,简化了开发过程。
  • 语言无关性:多数RPC框架支持多种编程语言,使得不同语言编写的服务可以互相通信。
  • 效率和抽象:RPC 抽象了通信细节,开发者可以专注于业务逻辑,同时RPC的设计通常优化了通信过程,提高远程调用效率。

3. 使用 RPC 的好处

  • 封装复杂性:RPC 隐藏了网络请求、数据序列化和反序列化的复杂性。
  • 提高开发效率:开发者可以如同进行本地函数调用一样进行远程调用,减少了学习和开发的复杂度。
  • 增强服务的可维护性:通过定义清晰的服务接口,RPC支持更好的服务版本控制和维护。

4. RPC 由哪几部分组成?

  • 客户端(Client):发起远程过程调用的一方。
  • 服务器端(Server):接收远程过程调用请求并处理的一方。
  • 通信协议:定义了客户端和服务器之间如何交换信息的规则。
  • 序列化机制:将对象或数据结构转换为可通过网络传输的格式的过程。
  • 网络传输:负责数据的发送和接收。

5. 示例:一个简单的 RPC 工程代码

这里使用 gRPC 和 Protobuf,gRPC 是一个高性能、开源和通用的 RPC 框架,由 Google 主导开发,支持多种编程语言。

步骤 1: 定义服务

首先,定义一个简单的服务,服务中有一个方法,返回客户端发送的消息。

service.proto:

syntax = "proto3";

package example;

// 定义一个 Greeter 服务
service Greeter {
  // 发送一个 Greeting 消息, 返回一个 GreetingResponse
  rpc Greet (Greeting) returns (GreetingResponse);
}

// Greeting 消息格式
message Greeting {
  string name = 1;
}

// GreetingResponse 消息格式
message GreetingResponse {
  string message = 1;
}

步骤 2: 生成服务代码

使用 protobuf 工具生成 C++ 代码。

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

步骤 3: 实现服务端

server.cpp:

#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#include "service.grpc.pb.h"

using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using example::Greeter;
using example::Greeting;
using example::GreetingResponse;

// 服务实现
class GreeterServiceImpl final : public Greeter::Service {
  Status Greet(ServerContext* context, const Greeting* request,
               GreetingResponse* 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::In

secureServerCredentials());
  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: 实现客户端

client.cpp:

#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#include "service.grpc.pb.h"

using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using example::Greeter;
using example::Greeting;
using example::GreetingResponse;

class GreeterClient {
public:
  GreeterClient(std::shared_ptr<Channel> channel)
      : stub_(Greeter::NewStub(channel)) {}

  // 同步调用 Greeter 服务
  std::string Greet(const std::string& user) {
    Greeting greeting; // 创建一个请求
    greeting.set_name(user);
    GreetingResponse response; // 存储回应
    ClientContext context;

    // 实际 RPC 调用
    Status status = stub_->Greet(&context, greeting, &response);

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

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

int main(int argc, char** argv) {
  GreeterClient greeter(grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()));
  std::string user("world");
  std::string reply = greeter.Greet(user);  // 发起 RPC 调用
  std::cout << "Greeter received: " << reply << std::endl;

  return 0;
}

运行结果

  1. 先运行服务器:./server
  2. 然后运行客户端:./client

客户端输出应该是:

Greeter received: Hello world

这个示例中,服务器和客户端通过 gRPC 通信,客户端发送一个字符串给服务器,服务器回复一个问候语。这个简单的例子演示了 RPC 的基本概念和流程。

示例中使用的gRPC 相关的类和组件讲解

1. grpc::Server

这是 gRPC 的核心类之一,用于构建和启动 RPC 服务端。它监听来自客户端的连接,处理收到的请求,并发送响应。Server 类配合 ServerBuilder 使用,用于配置端口、安全凭证等信息。

2. grpc::ServerBuilder

这个类用于构建 grpc::Server。它提供了一个流式接口(Fluent API),用于添加服务、配置监听端口、设置服务凭证等。一旦配置完成,可以调用 BuildAndStart() 方法来创建并启动一个 Server 实例。

3. grpc::ServerContext

这个类包含了 RPC 调用的上下文信息,例如客户端的元数据、取消状态等。它通常用于服务端方法的参数之一,以让方法能够访问和操作调用的上下文。

4. grpc::Status

Status 类用于表示 RPC 调用的结果。它包含一个状态码和一个可选的错误消息。在服务端,方法通过返回一个 Status 对象来告知客户端调用是成功还是失败。

示例中使用的example 命名空间中的类

这些类是由 Protocol Buffers(protobuf)编译器自动生成的,基于 .proto 文件中定义的服务和消息类型。

1. example::Greeter

这是一个由 protobuf 工具根据定义的 Greeter 服务自动生成的类。它包括服务端和客户端的桩(Stub)实现。

  • 服务端实现Greeter::Service 是一个抽象基类,定义了所有在 .proto 文件中指定的 RPC 方法。为了实现服务端,需要创建一个继承自 Greeter::Service 的类,并实现其所有虚拟方法。
  • 客户端桩:用于发起对服务的调用。Greeter::Stub 类提供了对应于服务中每个 RPC 方法的客户端调用实现。客户端通过这些方法发起 RPC 请求,并处理响应。

2. example::Greetingexample::GreetingResponse

这些类是根据 .proto 文件中定义的消息格式自动生成的。Greeting 用于客户端发送请求的数据结构,而 GreetingResponse 是服务端响应的数据结构。这些类包括了对消息字段的访问方法(如 set_name()message())以及序列化和反序列化的功能。

总结

在这个 RPC 示例中,example::Greeter 服务由 GreeterServiceImpl 类在服务器端实现,处理来自客户端的 Greet 方法调用。客户端通过 GreeterClient 类使用 Greeter::Stub 发起这些调用。使用 gRPC 框架和 protobuf 序列化机制,简化了跨网络的过程调用和数据交换的复杂性。这样,开发者可以专注于业务逻辑的实现,而无需深入了解底层网络通信的细节。

  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Warren++

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值