protobuf在rpc网络服务中的使用方法
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方法。
更多推荐


所有评论(0)