基于pb的rpc项目学习

转自: 如何基于protobuf实现一个极简版的RPC - Ying

1.介绍

pb是一种数据序列化方式。protobuf 实现了序列化部分,并且预留了 RPC 接口,但是没有实现网络交互的部分。

一次完整的 RPC 通信实际上是有三部分代码共同完成:

  1. protobuf 自动生成的代码
  2. RPC 框架
  3. 用户填充代码(Service的逻辑代码)

1.1 server端

server端需要继承并实现服务接口:

  virtual void Echo(::google::protobuf::RpcController* controller,
                       const ::echo::EchoRequest* request,
                       ::echo::EchoResponse* response,
                       ::google::protobuf::Closure* done);

1.2 client端

客户端通过EchoService_Stub发送数据,EchoService_Stub::Echo调用了::google::protobuf::Channel::CallMethod,但是Channel是一个纯虚类,需要 RPC 框架在子类里实现需要的功能。

// stub初始化时设置的数据成员
::google::protobuf::RpcChannel* channel_;

void EchoService_Stub::Echo(::google::protobuf::RpcController* controller,
                              const ::echo::EchoRequest* request,
                              ::echo::EchoResponse* response,
                              ::google::protobuf::Closure* done) {
  channel_->CallMethod(descriptor()->method(0),
                       controller, request, response, done);
}

RpcChannel的声明:

class LIBPROTOBUF_EXPORT RpcChannel {
 public:
  inline RpcChannel() {}
  virtual ~RpcChannel();

  // Call the given method of the remote service.  The signature of this
  // procedure looks the same as Service::CallMethod(), but the requirements
  // are less strict in one important way:  the request and response objects
  // need not be of any specific class as long as their descriptors are
  // method->input_type() and method->output_type().
  virtual void CallMethod(const MethodDescriptor* method,
                          RpcController* controller,
                          const Message* request,
                          Message* response,
                          Closure* done) = 0;

 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel);
};

1.3 参数控制rpcController

其中服务端和客户端都会用到rpcController类,它是一个纯虚类,需要框架自己继承实现。

RpcController 是一个控制对象,负责控制 RPC 的状态、错误信息等。客户端可以通过它来控制和查询调用的状态。

class MyController : public ::google::protobuf::RpcController {
public:
   // client端调用
  virtual void Reset() { };
   
   // client端调用判断服务运行结果
  virtual bool Failed() const { return false; };
    // 返回调用失败的原因,如果调用成功则返回空字符串
  virtual std::string ErrorText() const { return ""; };
  virtual void StartCancel() { };

   // 服务端: 当调用过程中遇到错误时,设置失败原因
  virtual void SetFailed(const std::string& /* reason */) { };
  virtual bool IsCanceled() const { return false; };
  virtual void NotifyOnCancel(::google::protobuf::Closure* /* callback */) { };
};//MyController

有些 RPC 框架在具体实现中会扩展 RpcController,例如添加流量控制或延迟信息的设置方法(如设置超时时间等)。

2.server端

考虑下 server 端的处理流程

  1. 从对端接收数据
  2. 通过标识机制判断如何反序列化到 request 数据类型
  3. 生成对应的 response 数据类型
  4. 调用对应的 service-method ,填充 response 数据
  5. 序列化 response
  6. 发送数据回对端

3.client端

rpcChannel 可以理解为一个通道,连接了 rpc 服务的两端,本质上也是通过 socket 通信的。RpcChannel也是一个纯虚类,CallMethod = 0

因此我们需要实现一个子类,基类为RpcChannel,并且实现CallMethod方法,应该实现两个功能:

  1. 序列化 request ,发送到对端,同时需要标识机制使得对端知道如何解析(schema)和处理(method)这类数据。
  2. 接收对端数据,反序列化到 response

此外还有RpcController,也是一个纯虚类,是一个辅助类,用于获取RPC结果,对端IP等。

猜你喜欢

转载自blog.csdn.net/huanting74/article/details/143097195