您的位置:首页 > 其它

以小见大——那些基于 protobuf 的五花八门的 RPC(3)

2011-04-12 17:03 543 查看
赖勇浩(http://laiyonghao.com


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
,全文如下:

package ProtoBufRemote;
message RpcMessage {
required int32 id = 1;
optional Call call_message = 2;
optional Result result_message = 3;
message Call {
required string service = 1;
required string method = 2;
repeated Parameter parameters = 3;
required bool expects_result = 4;
}
message Result {
optional bool is_failed = 1;
optional string error_message = 2;
optional Parameter call_result = 3;
}
message Parameter {
optional bytes proto_param = 1;
optional string string_param = 2;
optional sint32 int_param = 3;
optional uint32 uint_param = 4;
optional sint64 int64_param = 5;
optional uint64 uint64_param = 6;
optional bool bool_param = 7;
optional float float_param = 8;
optional double double_param = 9;
optional bool is_null = 10;
}
}


只有一个大定义: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
):

TEST_F(RpcClientTest, Call)
{
EXPECT_CALL(m_controller, Send(AllOf(Truly(IsCallMessageCorrect),
Property(&RpcMessage::call_message, Property(&RpcMessage::Call::expects_result, Eq(true))))))
.WillOnce(Invoke(this, &RpcClientTest::SendResult));
RpcMessage message;
MutableParameterList parameters(&message);
parameters.Add().SetInt(42);
PendingCall* call = m_client->Call("ServiceName", "MethodName", parameters);
call->Wait();
EXPECT_EQ(43, call->GetResult()->GetInt());
m_client->ReleaseCall(call);
}


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

rpc XXXX(RpcMessage)returns(RpcMessage);


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

parameters.Add().SetString(name);
parameters.Add().SetInt(id);
parameters.Add().SetString(email);


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

parameters.Add().SetProto(person);


可见各种方案都有利弊,获得了 rpc 声明的简洁,就需要牺牲代码的简洁为代价。虽然说作者的思路的确是如同天马行空般开阔,但如果是我的话,我不会采用这种方案,换作你呢,又会如何?

Call.expects_result 字段是告诉服务器端要不要把结果(包括是否出错)返回给客户端,很好理解。不过 Result.call_result 是 optional,而不是 repeated,让我觉得怪怪地,难道只准多个参数,不许多个返回值?

=====未完待续=====
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: