一元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");
在这个例子中,服务器返回了一个状态码为INTERNAL
的grpc::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的结果,或者因为某些条件已经改变,使得继续等待响应变得没有意义。取消可以用于各种情况,例如:
-
超时: 如果一个RPC调用超过了预定的时间还没有响应,客户端可能会选择取消它,以避免无限期地等待。
-
用户干预: 如果用户发起了一个操作,然后在操作完成前改变了主意,客户端应用可能需要取消相关的RPC调用。
-
资源优化: 如果客户端已经发送了多个RPC调用,但是得到了足够的信息来完成任务,它可能会取消剩余的调用,以节省服务器资源和网络带宽。
-
错误恢复: 如果在RPC调用过程中发生了错误,客户端可能会取消该调用,并尝试其他恢复策略。
-
依赖关系变化: 如果RPC调用的结果依赖于某些条件,而这些条件在调用过程中发生了变化,客户端可能需要取消调用。
取消RPC调用是异步编程中常见的一种模式,它允许应用程序更有效地管理资源和用户交互。在gRPC中,客户端可以通过调用grpc::ClientContext
的TryCancel
方法来取消RPC调用。服务端可以通过检查grpc::ServerContext::IsCancelled
来响应取消事件,并及时停止处理。
分享一个有趣的 学习链接:https://xxetb.xet.tech/s/HY8za