gRPC 四模式之 一元RPC模式

一元RPC模式

一元 RPC 模式也被称为简单 RPC 模式。在该模式中,当客户端调用服务器端的远程方法时,客户端发送请求至服务器端并获得一个响应,与响应一起发送的还有状态细节以及 trailer 元数据(这部分不是默认发送的,需要自己实现)

![[Pasted image 20231115104223.png]]

使用场景

单次通讯,传输数据包的时候,返回收到应答。

在一元RPC模式中,状态细节和trailer元数据并不是默认就有的,它们是由服务器端根据需要添加的。状态细节通常包含了关于RPC调用的状态信息,例如是否成功,如果失败了具体是什么原因等。而trailer元数据则是一些额外的信息,例如调用的时间,服务器的处理时间等。

具体来说,状态细节和trailer元数据的形式取决于你使用的RPC框架和编程语言。在gRPC中,状态细节和trailer元数据通常以键值对的形式存在,键和值都是字符串。例如,你可能会看到这样的状态细节:{"status": "success"},或者这样的trailer元数据:{"processing-time": "123ms"}

请注意,这只是一个例子,实际的状态细节和trailer元数据会根据你的应用需求和服务器的实现来定。

在gRPC中,服务器可以通过grpc::ServerContext对象来设置trailer元数据。这些元数据在RPC调用结束时发送给客户端。以下是一个C++的示例,展示了如何设置和发送trailer元数据:

cpp 复制代码
#include <grpcpp/grpcpp.h>
#include "your_service.grpc.pb.h"  // 替换为你的服务的protobuf头文件

class YourServiceImpl final : public YourService::Service {
  grpc::Status YourMethod(grpc::ServerContext* context, const YourRequest* request,
                          YourResponse* reply) override {
    // 处理你的方法逻辑...

    // 在RPC调用结束时,设置trailer元数据
    context->AddTrailingMetadata("processing-time", "123ms");

    return grpc::Status::OK;
  }
};

在这个例子中,服务器在处理完YourMethod方法后,通过AddTrailingMetadata方法添加了一个名为"processing-time"的trailer元数据,值为"123ms"。这个元数据会在RPC调用结束时发送给客户端。

至于状态细节,它通常包含在返回的grpc::Status对象中。例如,如果你的方法出现了错误,你可以返回一个包含错误信息的grpc::Status对象:

cpp 复制代码
return grpc::Status(grpc::StatusCode::INTERNAL, "An internal error occurred");

在这个例子中,服务器返回了一个状态码为INTERNALgrpc::Status对象,状态细节为"An internal error occurred"。这个状态细节会被发送给客户端,客户端可以通过检查返回的grpc::Status对象来获取这个信息。

在服务端返回时,设置多个状态和元数据

在gRPC中,你可以通过多次调用AddTrailingMetadata方法来添加多个trailer元数据。每次调用都会添加一个新的键值对。例如:

cpp 复制代码
context->AddTrailingMetadata("processing-time", "123ms");
context->AddTrailingMetadata("server-id", "server-001");
context->AddTrailingMetadata("timestamp", "2022-01-01T00:00:00Z");

在这个例子中,服务器添加了三个trailer元数据:"processing-time","server-id"和"timestamp"。

至于状态细节,gRPC的grpc::Status对象只支持设置一个状态细节。如果你需要传递多个状态信息,你可以将它们编码为一个字符串,例如JSON格式的字符串,然后设置为状态细节。例如:

cpp 复制代码
std::string status_detail = R"({
  "error": "An internal error occurred",
  "error_code": 123,
  "error_info": "Some additional info"
})";
return grpc::Status(grpc::StatusCode::INTERNAL, status_detail);

在这个例子中,服务器将多个状态信息编码为一个JSON格式的字符串,然后设置为状态细节。客户端可以解析这个字符串来获取这些状态信息。

客户端接取trailer元数据

客户端可以接收到服务端发送的trailer元数据和状态细节,并根据需要进行处理。

在gRPC中,客户端可以通过grpc::ClientContext对象来获取trailer元数据。例如:

cpp 复制代码
grpc::ClientContext context;
YourResponse response;
grpc::Status status = stub->YourMethod(&context, request, &response);

if (!status.ok()) {
  std::cout << "RPC failed with code " << status.error_code()
            << ", message: " << status.error_message() << std::endl;

  // 获取trailer元数据
  auto trailers = context.GetServerTrailingMetadata();
  for (const auto& kv : trailers) {
    std::cout << "Trailer key: " << kv.first << ", value: " << kv.second << std::endl;
  }
}

在这个例子中,客户端首先调用YourMethod方法并获取返回的grpc::Status对象。如果RPC调用失败,客户端会打印出错误信息,然后通过GetServerTrailingMetadata方法获取trailer元数据并打印出来。

至于状态细节,客户端可以通过grpc::Status对象的error_message方法来获取。例如:

cpp 复制代码
std::cout << "Status detail: " << status.error_message() << std::endl;

在这个例子中,客户端打印出了状态细节。如果状态细节是一个编码的字符串,例如JSON格式的字符串,客户端可以解析这个字符串来获取状态信息。

客户端发送 header 元数据、状态细节

在gRPC中,客户端也可以设置和发送header元数据和状态细节。这可以通过grpc::ClientContext对象来实现。

首先,客户端可以通过AddMetadata方法来设置header元数据:

cpp 复制代码
grpc::ClientContext context;
context.AddMetadata("client-id", "client-001");
context.AddMetadata("timestamp", "2022-01-01T00:00:00Z");

在这个例子中,客户端设置了两个header元数据:"client-id"和"timestamp"。

然后,客户端可以通过TryCancel方法来取消RPC调用,并通过set_cancel_message方法来设置状态细节:

cpp 复制代码
context.TryCancel();
context.set_cancel_message("The request was cancelled by the client");

在这个例子中,客户端取消了RPC调用,并设置了状态细节为"The request was cancelled by the client"。

请注意,这只是一个例子,实际的使用方式会根据你的应用需求和gRPC的API来定。在gRPC中,客户端也可以设置和发送header元数据和状态细节。这可以通过grpc::ClientContext对象来实现。

首先,客户端可以通过AddMetadata方法来设置header元数据:

cpp 复制代码
grpc::ClientContext context;
context.AddMetadata("client-id", "client-001");
context.AddMetadata("timestamp", "2022-01-01T00:00:00Z");

在这个例子中,客户端设置了两个header元数据:"client-id"和"timestamp"。

然后,客户端可以通过TryCancel方法来取消RPC调用,并通过set_cancel_message方法来设置状态细节:

cpp 复制代码
context.TryCancel();
context.set_cancel_message("The request was cancelled by the client");

在这个例子中,客户端取消了RPC调用,并设置了状态细节为"The request was cancelled by the client"。

补充:

取消RPC调用通常是因为客户端不再需要RPC的结果,或者因为某些条件已经改变,使得继续等待响应变得没有意义。取消可以用于各种情况,例如:

  1. 超时: 如果一个RPC调用超过了预定的时间还没有响应,客户端可能会选择取消它,以避免无限期地等待。

  2. 用户干预: 如果用户发起了一个操作,然后在操作完成前改变了主意,客户端应用可能需要取消相关的RPC调用。

  3. 资源优化: 如果客户端已经发送了多个RPC调用,但是得到了足够的信息来完成任务,它可能会取消剩余的调用,以节省服务器资源和网络带宽。

  4. 错误恢复: 如果在RPC调用过程中发生了错误,客户端可能会取消该调用,并尝试其他恢复策略。

  5. 依赖关系变化: 如果RPC调用的结果依赖于某些条件,而这些条件在调用过程中发生了变化,客户端可能需要取消调用。

取消RPC调用是异步编程中常见的一种模式,它允许应用程序更有效地管理资源和用户交互。在gRPC中,客户端可以通过调用grpc::ClientContextTryCancel方法来取消RPC调用。服务端可以通过检查grpc::ServerContext::IsCancelled来响应取消事件,并及时停止处理。


分享一个有趣的 学习链接:https://xxetb.xet.tech/s/HY8za

相关推荐
点点滴滴的记录9 小时前
RPC核心实现原理
网络·网络协议·rpc
徒步僧9 小时前
ThingsBoard规则链节点:RPC Call Reply节点详解
qt·microsoft·rpc
程思扬10 小时前
为什么Uptime+Kuma本地部署与远程使用是网站监控新选择?
linux·服务器·网络·经验分享·后端·网络协议·1024程序员节
海绵波波10711 小时前
Webserver(4.8)UDP、广播、组播
单片机·网络协议·udp
很透彻13 小时前
【网络】传输层协议TCP(下)
网络·c++·网络协议·tcp/ip
蝌蚪代理ip15 小时前
辩论赛——动态IP与静态IP的巅峰对决
网络·网络协议·tcp/ip·ip
dulu~dulu17 小时前
查缺补漏----用户上网过程(HTTP,DNS与ARP)
网络·网络协议·http
丶213618 小时前
【网络】HTTP(超文本传输协议)详解
网络·网络协议·http
坚持拒绝熬夜18 小时前
IP协议知识点总结
网络·笔记·网络协议·tcp/ip
C++忠实粉丝1 天前
计算机网络socket编程(1)_UDP网络编程实现echo server
linux·服务器·网络·c++·网络协议·计算机网络·udp