protobuf简介:

        它是一种序列化和反序列化协议,常见序列化和反序列化协议有XML、JSON、PB,相比于其他是文本存储,PB更有优势:跨平台语言支持,可以由C++传输到java,序列化和反序列化效率高速度快,因为是二进制存储且序列化后体积比XML和JSON都小很多,适合网络传输,XML逐渐弃用,JSON是键值存储方式,有额外的无用信息。

代码使用示例:

        protobuf需要根据它的语法进行手动定义它的内容:主要定义消息(message)和枚举(enum)和定义服务(service)

syntax = "proto3"; // 设置版本 必需
package raftRpcProctoc; //所在的命名空间
option cc_generic_services = true;  //启用C++泛型服务,编译成pd.cc 时会根据服务定义生成一些泛型的代码,其中包括客户端和服务器端的基本框架


message Person{
  	required bytes name = 1;
 	required int32 id = 2;
    optional string email = 3;
} // 一个消息类型,会被编译为C++的类,required表示该类型必需,optional表示非必需,一般用bytes而不用

service raftRpc  
{
    rpc AppendEntries(AppendEntriesArgs) returns(AppendEntriesReply);
    rpc InstallSnapshot (InstallSnapshotRequest) returns (InstallSnapshotResponse);
    rpc RequestVote (RequestVoteArgs) returns (RequestVoteReply);
} 

        这儿就是service的定义,和option cc_generic_services = true相辅相成,rpc是用于定义 RPC 服务接口的语法标记,声明一个远程过程调用方法,类似的远程调用技术还有RESTful API、gRPC。第二个方法名称,即函数名称,然后就是函数参数的类型和返回参数的类型,注意这儿并不意味着它的函数参数为RequestVoteArgs类型,返回RequestVoteReply,而是在这个服务定义中,RequestVoteArgs是请求消息类型,表示客户端发送给服务器的请求消息,RequestVoteReply是响应消息类型,表示服务器发送给客户端的响应消息。所以使用时:在 C++ 中,服务接口会被编译成一个抽象类,使用时需要继承这个抽象类,并重写其中定义的服务方法,来实现具体的 RPC 服务逻辑。

编译指令:编译成C++相关的头文件和源文件

protoc --cpp_out=. person.proto

上述编译得到两个类:raftRpc 和 raftRpc_stub

raftRpc类是因为在.proto文件中定义了raftRpc服务而生成的,raftRpc类继承于google::protobuf::Service类,供callee–>rpc服务提供者使用,如下所示:

class raftRpc : public ::PROTOBUF_NAMESPACE_ID::Service {
 protected:
  // This class should be treated as an abstract interface.
  inline raftRpc() {};//构造函数声明为 inline raftRpc() {},并在 protected 访问级别下。这意味着该类不能被直接实例化,而是作为抽象接口类使用,符合服务定义
 public:
  virtual ~raftRpc();

  typedef raftRpc_Stub Stub;

  static const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor* descriptor();

 // 类中三个方法均为虚函数,表示让派生类重写,(被raftRpc_stub重写)
  virtual void AppendEntries(::PROTOBUF_NAMESPACE_ID::RpcController* controller, const ::raftRpcProctoc::AppendEntriesArgs* request,
                       ::raftRpcProctoc::AppendEntriesReply* response,
                       ::google::protobuf::Closure* done);
  virtual void InstallSnapshot(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::raftRpcProctoc::InstallSnapshotRequest* request,
                       ::raftRpcProctoc::InstallSnapshotResponse* response,
                       ::google::protobuf::Closure* done);
  virtual void RequestVote(::PROTOBUF_NAMESPACE_ID::RpcController* controller, const ::raftRpcProctoc::RequestVoteArgs* request,
                       ::raftRpcProctoc::RequestVoteReply* response,
                       ::google::protobuf::Closure* done);

  // implements Service ----------------------------------------------

  const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor* GetDescriptor();
  void CallMethod(const ::PROTOBUF_NAMESPACE_ID::MethodDescriptor* method,
                  ::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                  const ::PROTOBUF_NAMESPACE_ID::Message* request,
                  ::PROTOBUF_NAMESPACE_ID::Message* response,
                  ::google::protobuf::Closure* done);
  const ::PROTOBUF_NAMESPACE_ID::Message& GetRequestPrototype(
    const ::PROTOBUF_NAMESPACE_ID::MethodDescriptor* method) const;
  const ::PROTOBUF_NAMESPACE_ID::Message& GetResponsePrototype(
    const ::PROTOBUF_NAMESPACE_ID::MethodDescriptor* method) const;

 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(raftRpc);
};

raftRpc_stub定义如下,它是继承至raftRpc的,供caller–>rpc服务的调用者使用

其拥有一个RpcChannel(注意名字和什么对应)类型的指针变量,在构造时需要传入这个值(没有默认构造函数!)。

class raftRpc_Stub : public raftRpc {
 public:
  raftRpc_Stub(::PROTOBUF_NAMESPACE_ID::RpcChannel* channel);
  raftRpc_Stub(::PROTOBUF_NAMESPACE_ID::RpcChannel* channel,
                   ::PROTOBUF_NAMESPACE_ID::Service::ChannelOwnership ownership);
  ~raftRpc_Stub();

  inline ::PROTOBUF_NAMESPACE_ID::RpcChannel* channel() { return channel_; }

  // implements raftRpc ------------------------------------------
  // 以下三个成员函数 都是继承自基类的函数,在.cc中实现时都调用了channel的CallMethod函数
  void AppendEntries(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                       const ::raftRpcProctoc::AppendEntriesArgs* request,
                       ::raftRpcProctoc::AppendEntriesReply* response,
                       ::google::protobuf::Closure* done);
  void InstallSnapshot(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                       const ::raftRpcProctoc::InstallSnapshotRequest* request,
                       ::raftRpcProctoc::InstallSnapshotResponse* response,
                       ::google::protobuf::Closure* done);
  void RequestVote(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                       const ::raftRpcProctoc::RequestVoteArgs* request,
                       ::raftRpcProctoc::RequestVoteReply* response,
                       ::google::protobuf::Closure* done);
 private:
  ::PROTOBUF_NAMESPACE_ID::RpcChannel* channel_;
  bool owns_channel_;
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(raftRpc_Stub);
};

Rpcchannel是一个抽象类!其包含一个CallMethod()虚函数:

class PROTOBUF_EXPORT RpcChannel {
 public:
  inline RpcChannel() {}
  virtual ~RpcChannel();
  virtual void CallMethod(const MethodDescriptor* method,
                          RpcController* controller, const Message* request,
                          Message* response, Closure* done) = 0;
 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel);
};

因此最终是:一切的源头只需要一个RpcChannel类,由于派生类是可以用基类指针指向的(多态),因此stub桩类不管调用哪个方法,最终都调用到我们的MyRpcChannel的CallMethod方法,我们在这里就可以进行rpc方法的序列化和反序列化,然后发起远程的rpc调用请求。所以框架的实现重点就在于RpcChannel的CallMethod方法。

更多推荐