muduo 使用网络库和 Protobuf 来构建 RPC 框架
通过阅读moduo中rpc的示例程序来分析,如何利用一个网络库和Protobuf来构建一个RPC框架
pb generated sources
分析pb生成了哪些源码,思考需要用网络库去实现哪部分来实现通信
sudoku.proto
package sudoku;
option cc_generic_services = true;
option java_generic_services = true;
option py_generic_services = true;
message SudokuRequest {
required string checkerboard = 1;
}
message SudokuResponse {
optional bool solved = 1 [default=false];
optional string checkerboard = 2;
}
service SudokuService {
rpc Solve (SudokuRequest) returns (SudokuResponse);
}
sudoku.proto.h & sudoku.proto.cc
SudokuService
class SudokuService : public ::PROTOBUF_NAMESPACE_ID::Service {
protected:
// This class should be treated as an abstract interface.
inline SudokuService() {
};
public:
virtual ~SudokuService();
typedef SudokuService_Stub Stub;
static const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor* descriptor();
virtual void Solve(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
const ::sudoku::SudokuRequest* request,
::sudoku::SudokuResponse* 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(SudokuService);
};
SudokuService
override 了父类 Service
的纯虚函数
// Abstract base interface for protocol-buffer-based RPC services. Services
// themselves are abstract interfaces (implemented either by servers or as
// stubs), but they subclass this base interface. The methods of this
// interface can be used to call the methods of the Service without knowing
// its exact type at compile time (analogous to Reflection).
class PROTOBUF_EXPORT Service {
public:
inline Service() {
}
virtual ~Service();
...
// Get the ServiceDescriptor describing this service and its methods.
virtual const ServiceDescriptor* GetDescriptor() = 0;
virtual void CallMethod(const MethodDescriptor* method,
RpcController* controller, const Message* request,
Message* response, Closure* done) = 0;
virtual const Message& GetRequestPrototype(
const MethodDescriptor* method) const = 0;
virtual const Message& GetResponsePrototype(
const MethodDescriptor* method) const = 0;
...
};
descriptor
每一种具体的 Service
类(SudokuService)或 Method
(Solve) 或 Message
类 (SudokuRequest, SudokuResponse)类都会对应一个全局唯一的 ServiceDescriptor
常量实例或MethodDescriptor
常量实例或Descriptor
常量实例,用来获取该 ConcreteType 的各种信息
ServiceDescriptor
通过GetDescriptor()
这个接口,可以获取到指向SudokuService
对应的全局唯一的ServiceDescriptor
常量实例的指针(const ServiceDescriptor*)
const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor* SudokuService::GetDescriptor() {
return descriptor();
}
通过ServiceDescriptor
就可以获取service name,以及指向service所包含的methods各自对应的一个全局唯一MethodDescriptor
常量实例的指针(const MethodDescriptor*)
class PROTOBUF_EXPORT ServiceDescriptor {
public:
...
// The name of the service, not including its containing scope.
const std::string& name() const;
// The fully-qualified name of the service, scope delimited by periods.
const std::string& full_name() const;
...
// The number of methods this service defines.
int method_count() const;
// Gets a MethodDescriptor by index, where 0 <= index < method_count().
// These are returned in the order they were defined in the .proto file.
const MethodDescriptor* method(int index) const;
// Look up a MethodDescriptor by name.
const MethodDescriptor* FindMethodByName(ConstStringParam name) const;
...
};
MethodDescriptor
通过MethodDescriptor
可以获取method name,指向该method所属的service所对应的全局唯一的ServiceDescriptor
常量实例的指针(const ServiceDescriptor*),以及指向该method的input message和output message各自所对应的全局唯一的Descriptor
常量实例指针(const Descriptor*)
class PROTOBUF_EXPORT MethodDescriptor {
public:
...
// Name of this method, not including containing scope.
const std::string& name() const;
// The fully-qualified name of the method, scope delimited by periods.
const std::string& full_name() const;
...
// Gets the service to which this method belongs. Never nullptr.
const ServiceDescriptor* service() const;
// Gets the type of protocol message which this method accepts as input.
const Descriptor* input_type() const;
// Gets the type of protocol message which this message produces as output.
const Descriptor* output_type() const;
...
};
Descriptor
method
Solve
是SudokuService
中唯一的method,它是个虚函数,需要业务来继承SudokuService
这个类并且 override Solve
方法,来实现业务逻辑(接受 request,set response)。done->Run()
(Closure
是个纯虚类,需要RPC框架来实现)的时候应该要能把response序列化后返回给client(返回RPC响应报文)。
class SudokuServiceImpl : public SudokuService
{
public:
void Solve(::google::protobuf::RpcController* controller,
const ::sudoku