`

(转)Protobuf+RPC的几个C++实现

 
阅读更多

1. RCF: 纯c++的RPC, 不引入IDL, 大量用到boost,比较强大.
2. casocklib:  protobuf + asio 较完善实现
3. eventrpc: protobuf + libevent 较完善实现
4. evproto: protobuf + libevent 简单实现
5. febird:同样无IDL的c++ RPC,自己实现了串行化和网络IO.
6. libHttp, xmlrpc 都是xml封装的RPC

 

以下是某专家的详解:

http://blog.csdn.net/lanphaday/archive/2011/04/12/6318432.aspx

(原文还包括java,python)

 

casocklib

先看它的简介:An asynchronous communication library for C++,而它基本包格式见:http://code.google.com/p/casocklib/source/browse/trunk/src/casock/rpc/protobuf/api/rpc.proto ,如下:

  1. package casock.rpc.protobuf.api;  
  2. enum ResponseType {  
  3.   RESPONSE_TYPE_OK = 1;  
  4.   RESPONSE_TYPE_ERROR = 2;  
  5. };  
  6. message RpcRequest {  
  7.   required uint32 id = 1;  
  8.   required string operation = 2;  
  9.   optional bytes request = 3;  
  10. }  
  11. message RpcResponse {  
  12.   required uint32 id = 1;  
  13.   required ResponseType type = 2;  
  14.   optional bytes response = 3;  
  15. }  


代码很短,采用了相当轻量级的设计。首先旗帜鲜明地声明了响应包的种类:成功以及失败,对于失败,并没有细分。RpcRequest.id 使用 32 位无符号整型,跟 protobuf-rpc 一样,不过这里的 operation 却跟后者的 method 不一样,operation 是货真价实的 MethodDescriptor.name,从代码(http://code.google.com/p/casocklib/source/browse/trunk/src/casock/rpc/protobuf/client/RPCRequestBuilder.cc#50 )可以证实。因为每一个 RpcRequest.operation 都不带 service name,所以使用 Casocklib 是无法将多个 service host 到同一个端口的。
RpcResponse 因为带了一个 ResponseType,所以可以知道 method 到底有没有执行成功,同理 response 就设计成 optional 了,因为执行错误就不需要返回 response 了呀

 

protobuf-remote

嘎~再来一枚 C++ 系的 RPC,它的简介是 RPC implementation for C# and C++ using Protocol Buffers,比之前的几个 rpc 实现都要复杂。基本格式见:http://code.google.com/p/protobuf-remote/source/browse/Cpp/Source/ProtoBufRemote/RpcMessage.proto ,全文如下

  1. package ProtoBufRemote;  
  2. message RpcMessage {  
  3.   required int32 id = 1;  
  4.   optional Call call_message = 2;  
  5.   optional Result result_message = 3;  
  6.   message Call {  
  7.     required string service = 1;  
  8.     required string method = 2;  
  9.         repeated Parameter parameters = 3;  
  10.         required bool expects_result = 4;  
  11.   }  
  12.   message Result {  
  13.     optional bool is_failed = 1;  
  14.         optional string error_message = 2;  
  15.     optional Parameter call_result = 3;  
  16.   }  
  17.   message Parameter {  
  18.         optional bytes proto_param = 1;  
  19.     optional string string_param = 2;  
  20.         optional sint32 int_param = 3;  
  21.         optional uint32 uint_param = 4;  
  22.         optional sint64 int64_param = 5;  
  23.         optional uint64 uint64_param = 6;  
  24.         optional bool bool_param = 7;  
  25.         optional float float_param = 8;  
  26.         optional double double_param = 9;  
  27.         optional bool is_null = 10;  
  28.   }  
  29. }  

只有一个大定义:message RpcMessage,它即是 request 又是 response,这一点跟之前的 protobuf-rpc 的 Rpc 相同;但不同的是它把 id 从 call/result(对应常用的 request/response)中抽取出来作为 RpcMessage 的共有属性,不过我没看到它的做法的时候,还真没想过要抽取出来,看来我重构能力有待加强。
从 Call 来看,采用了 service 和 method 分开两个字段的设计,所以 multi-service 是没有问题的。repeated Parameter parameters 让我有点困惑,因为之前所看的设计,应该都是使用 bytes 存储序列化好的 message 对象,那么这个 parameters 是否有独到之处,有的话又是什么呢?抱着这样的疑惑,我翻开了它的代码(额,测试代码,因为简单好懂,见:http://code.google.com/p/protobuf-remote/source/browse/Cpp/Source/ProtoBufRemoteTest/RpcClientTest.cpp#76 ):

  1. TEST_F(RpcClientTest, Call)  
  2. {  
  3.         EXPECT_CALL(m_controller, Send(AllOf(Truly(IsCallMessageCorrect),  
  4.                 Property(&RpcMessage::call_message, Property(&RpcMessage::Call::expects_result, Eq(true))))))  
  5.                 .WillOnce(Invoke(this, &RpcClientTest::SendResult));  
  6.         RpcMessage message;  
  7.         MutableParameterList parameters(&message);  
  8.         parameters.Add().SetInt(42);  
  9.         PendingCall* call = m_client->Call("ServiceName", "MethodName", parameters);  
  10.         call->Wait();  
  11.         EXPECT_EQ(43, call->GetResult()->GetInt());  
  12.         m_client->ReleaseCall(call);  
  13. }  


可以看到声明了一个 RpcMessage 变量,然后用它实例化了一个 MutableParameterList(这个 MutablePararmeterList 可以看作是 Call.parameters 的适配器),然后往里加入了一个整型参数 42,然后再调用 Call 方法把请求发送到服务器端。至此我们可以明白 parameters 的作用是让我们声明 rpc 的时候,不再需要详细定义相应的参数和返回值类型了,统一写成:

  1. rpc XXXX(RpcMessage)returns(RpcMessage);  


即可,唯一需要变化的是用真正的方法名替换掉 XXXX。而 repeated Parameter parameters 中 repeated 的作用是为了传入复合参数,比如按常规传入 protobuf 官方示例中的 message Person 参数的话,可能在这里是这样的:

  1. parameters.Add().SetString(name);  
  2. parameters.Add().SetInt(id);  
  3. parameters.Add().SetString(email);  


不过如果有定义 message Person 的话,也可以这样:

  1. parameters.Add().SetProto(person);  


可见各种方案都有利弊,获得了 rpc 声明的简洁,就需要牺牲代码的简洁为代价。虽然说作者的思路的确是如同天马行空般开阔,但如果是我的话,我不会采用这种方案,换作你呢,又会如何?
Call.expects_result 字段是告诉服务器端要不要把结果(包括是否出错)返回给客户端,很好理解。不过 Result.call_result 是 optional,而不是 repeated,让我觉得怪怪地,难道只准多个参数,不许多个返回值?

 

server1

server1 出自国人之手,是一个利用了 Boost 的 a c++ network server/client framework,它的作者 xiliu tang 是我的前同事。server1 的代码还是非常简明的,先来看一下基础格式:http://code.google.com/p/server1/source/browse/trunk/server/meta.proto ,全文如下:

  1. package ProtobufLineFormat;  
  2. message MetaData {  
  3.   enum Type {  
  4.     REQUEST = 1;  
  5.     RESPONSE = 2;  
  6.   };  
  7.   required Type type = 1;  
  8.   required uint64 identify = 2;  
  9.   // the request should bring the response identify.  
  10.   optional uint64 response_identify = 3;  
  11.   required bytes content = 4;  
  12. };  


很简单,只有一个 message MetaData?对的。感觉上跟 protobuf-rpc 差不多,两个不同:一是 MetaData 带了一个 Type,用来标明它是请求还是响应;还有一个是 MetaData 使用了无符号 64 位整型作为 ID。使用 type 字段我个人感觉比 repeated/optional 的方式比起来有点没有充分利用到 protobuf 特性的感觉,不过相当地清晰明了。还有就是 response_identify 我专门在 GTalk 上问过作者,他说记不起为什么要加这个字段了……囧。我的看法是这个字段是不必要的。嗯,这个设计真的很简洁,不过,我不喜欢 Meta 这个命名。

 

 

 

 

 

 

 

 

 

分享到:
评论
1 楼 chd_wu 2011-07-22  
都不如protobuf配合zmq啊

相关推荐

    protobuf源码和静态库,环境为Windows平台X64

    在Windows平台上,protobuf的使用主要包括以下几个步骤: 1. **下载与安装**: 压缩包中的"protobuf_x64-windows"可能包含了预编译的protobuf静态库,这使得用户无需自行编译,可以直接在64位的Windows环境下使用。...

    手写rpc rpc简单源码 rpc源码学习 rpc过程了解 rpc通信原理

    在手写RPC的过程中,我们需要关注以下几个关键步骤: 1. **接口定义**:定义客户端和服务端共享的接口,这通常是通过idl(Interface Definition Language)完成。 2. **序列化/反序列化实现**:选择或实现合适的...

    protobuf-3.13.0.zip

    在这个3.13.0版本中,我们主要可以探索以下几个关键知识点: 1. **protobuf语言定义**:protobuf提供了一种简单的声明性语言,用于定义数据结构。开发者可以在.proto文件中定义消息类型,这些文件类似于接口定义...

    protobuf-3.3.0_X86库.rar

    描述中提到的几个关键点是: 1. **C++与JAVA数据交换**:protobuf的主要功能之一就是跨平台的数据交换。它允许你在不同的编程语言之间创建一致的数据模型,使得C++和JAVA程序可以方便地共享和解析数据。 2. **protoc...

    rpc调用的一个demo

    RPC调用通常包含以下几个步骤: 1. **请求构建**:客户端根据接口定义,打包请求数据。 2. **序列化**:将请求对象转换为网络可传输的字节流。 3. **网络传输**:通过TCP/IP协议或其他网络协议,将序列化的请求发送...

    protobuf-java-3.4.0.zip

    总之,protobuf-java-3.4.0.zip是一个包含protobuf Java实现3.4.0版本的压缩包,提供了一整套工具和库,使得Java开发者能够利用protobuf的强大功能进行数据序列化和通信。通过学习和使用这个版本,你可以提高你的...

    A simple C++ based RPC framework..zip

    在C++中实现RPC,我们需要关注以下几个核心部分: 1. **序列化与反序列化**:RPC框架需要将参数和返回值转换为可传输的格式,如二进制或JSON。在C++中,可以使用如protobuf(Protocol Buffers)、XML、JSON库等来...

    protobuf-python-3.8.0.tar.gz

    在 Python 中使用 Protobuf,主要涉及以下几个知识点: 1. **Protobuf 编译器**:protobuf-compiler 是一个命令行工具,用于将 .proto 文件编译成不同语言(如 Python、Java、C++)的源代码。在这个压缩包中,可能...

    protobuf-3.3.0-java

    在压缩包内的文件名称列表中,虽然没有具体的文件名,但通常一个protobuf的发行版会包含以下几类文件: 1. `protoc.jar`:protobuf的编译器,用于将.proto文件转换为对应语言(如Java、C++、Python等)的源代码。 2...

    linux protobuf

    在"linux protobuf"这个主题中,我们可以讨论以下几个重要的知识点: 1. **protobuf的安装与配置**:在Linux系统中,首先需要从官网或者通过给定的压缩包`protobuf-2.5.0`下载protobuf的源码。解压后,执行常规的...

    RPC调用框架比较分析

    - **protobuf-rpc-pro-demo-1.1.0及源码.zip** 包含了一个基于Protobuf实现的RPC框架的示例项目和源代码,版本为1.1.0,可以帮助开发者快速理解和应用Protobuf RPC。 Protobuf RPC的优势在于它具有高效的序列化...

    protobufdemo

    在这个"protobufdemo"项目中,我们可以预见到以下几个关键知识点: 1. **Protocol Buffers基础**:首先,我们需要理解protobuf的基本概念,包括.proto文件的编写,它是protobuf的数据结构定义文件,包含了消息类型...

    protobuf-3.5.1 下载 最新

    描述中提到的"protobuf-3.5.1.jar"是protobuf的Java实现库,表明这个版本适用于Java开发者。"版本目前最新"意味着在发布该资源时,这是protobuf的最新稳定版本,通常会包含最新的特性和修复的bug。"是从外网官网下载...

    protobuf-2.5.0.zip

    标题 "protobuf-2.5.0.zip" 指向的是Protocol Buffers(简称protobuf)的一个特定版本,即2.5.0。Protocol Buffers是Google开发的一种数据序列化协议,用于高效、跨平台地存储和传输结构化数据。描述中的内容 ...

    sublime支持protobuf插件.zip

    protobuf文件编译成目标语言(如C++, Java, Python等)的代码,这样程序就可以解析和序列化protobuf消息。Google提供了protoc编译器,它读取.proto文件并生成相应的代码。生成的代码通常包括解析和序列化消息的函数...

    protobuf-3.5.1.zip

    protobuf的使用流程通常包括以下几个步骤: 1. 定义数据结构:创建.proto文件,声明消息类型和其他数据结构。 2. 生成源代码:使用protoc将.proto文件编译成目标语言的源代码。 3. 编写应用程序:在生成的源代码基础...

    java序列化之protobuf

    与Java默认的序列化机制相比,protobuf有几个显著优点: 1. 性能:protobuf序列化和反序列化速度比Java序列化快很多。 2. 数据大小:protobuf编码的数据通常比JSON或XML更小,节省了存储和网络传输成本。 3. 版本...

    PyPI 官网下载 | protobuf-3.19.0rc2-cp36-cp36m-macosx_10_9_x86_64.whl

    protobuf的使用方法包括以下几个步骤: 1. 安装protobuf库:在命令行中输入`pip install protobuf-3.19.0rc2-cp36-cp36m-macosx_10_9_x86_64.whl`,即可完成protobuf的安装。 2. 定义消息类型:使用protobuf的语法...

    protobuf-cpp-3.6.1.zip

    在protobuf 3.6.1版本中,我们可以深入探讨以下几个关键知识点: 1. **protobuf语法**:protobuf使用类似XML的语法规则定义消息类型。通过`.proto`文件,开发者可以声明字段类型、字段名和编号,构建出复杂的结构化...

    protobuf-2.6.1

    在protobuf的使用过程中,主要包括以下几个步骤: 1. **定义数据结构**:在.proto文件中,开发者用protobuf语法定义消息类型,包括字段类型、名称和编号。例如: ```proto message Person { required string ...

Global site tag (gtag.js) - Google Analytics