1. RCF: 純c++的RPC, 不引入IDL, 大量用到boost,比較強(qiáng)大.
2. casocklib: protobuf + asio 較完善實(shí)現(xiàn)
3. eventrpc: protobuf + libevent 較完善實(shí)現(xiàn)
4. evproto: protobuf + libevent 簡(jiǎn)單實(shí)現(xiàn)
5. febird:同樣無(wú)IDL的c++ RPC,自己實(shí)現(xiàn)了串行化和網(wǎng)絡(luò)IO.
6. libHttp, xmlrpc 都是xml封裝的RPC
以下是某專(zhuān)家的詳解:
http://blog.csdn.net/lanphaday/archive/2011/04/12/6318432.aspx(原文還包括java,python)
casocklib
先看它的簡(jiǎn)介:An asynchronous communication library for C++,而它基本包格式見(jiàn):
http://code.google.com/p/casocklib/source/browse/trunk/src/casock/rpc/protobuf/api/rpc.proto ,如下:
view plaincopy to clipboardprint?package casock.rpc.protobuf.api;
enum ResponseType {
RESPONSE_TYPE_OK = 1;
RESPONSE_TYPE_ERROR = 2;
};
message RpcRequest {
required uint32 id = 1;
required string operation = 2;
optional bytes request = 3;
}
message RpcResponse {
required uint32 id = 1;
required ResponseType type = 2;
optional bytes response = 3;
}
代碼很短,采用了相當(dāng)輕量級(jí)的設(shè)計(jì)。首先旗幟鮮明地聲明了響應(yīng)包的種類(lèi):成功以及失敗,對(duì)于失敗,并沒(méi)有細(xì)分。RpcRequest.id 使用 32 位無(wú)符號(hào)整型,跟 protobuf-rpc 一樣,不過(guò)這里的 operation 卻跟后者的 method 不一樣,operation 是貨真價(jià)實(shí)的 MethodDescriptor.name,從代碼(
http://code.google.com/p/casocklib/source/browse/trunk/src/casock/rpc/protobuf/client/RPCRequestBuilder.cc#50 )可以證實(shí)。因?yàn)槊恳粋€(gè) RpcRequest.operation 都不帶 service name,所以使用 Casocklib 是無(wú)法將多個(gè) service host 到同一個(gè)端口的。
RpcResponse 因?yàn)閹Я艘粋€(gè) ResponseType,所以可以知道 method 到底有沒(méi)有執(zhí)行成功,同理 response 就設(shè)計(jì)成 optional 了,因?yàn)閳?zhí)行錯(cuò)誤就不需要返回 response 了呀
protobuf-remote
嘎~再來(lái)一枚 C++ 系的 RPC,它的簡(jiǎn)介是 RPC implementation for C# and C++ using Protocol Buffers,比之前的幾個(gè) rpc 實(shí)現(xiàn)都要復(fù)雜?;靖袷揭?jiàn):
http://code.google.com/p/protobuf-remote/source/browse/Cpp/Source/ProtoBufRemote/RpcMessage.proto ,全文如下:
view plaincopy to clipboardprint?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;
}
}
只有一個(gè)大定義:message RpcMessage,它即是 request 又是 response,這一點(diǎn)跟之前的 protobuf-rpc 的 Rpc 相同;但不同的是它把 id 從 call/result(對(duì)應(yīng)常用的 request/response)中抽取出來(lái)作為 RpcMessage 的共有屬性,不過(guò)我沒(méi)看到它的做法的時(shí)候,還真沒(méi)想過(guò)要抽取出來(lái),看來(lái)我重構(gòu)能力有待加強(qiáng)。
從 Call 來(lái)看,采用了 service 和 method 分開(kāi)兩個(gè)字段的設(shè)計(jì),所以 multi-service 是沒(méi)有問(wèn)題的。repeated Parameter parameters 讓我有點(diǎn)困惑,因?yàn)橹八吹脑O(shè)計(jì),應(yīng)該都是使用 bytes 存儲(chǔ)序列化好的 message 對(duì)象,那么這個(gè) parameters 是否有獨(dú)到之處,有的話又是什么呢?抱著這樣的疑惑,我翻開(kāi)了它的代碼(額,測(cè)試代碼,因?yàn)楹?jiǎn)單好懂,見(jiàn):
http://code.google.com/p/protobuf-remote/source/browse/Cpp/Source/ProtoBufRemoteTest/RpcClientTest.cpp#76 ):
view plaincopy to clipboardprint?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);
}
可以看到聲明了一個(gè) RpcMessage 變量,然后用它實(shí)例化了一個(gè) MutableParameterList(這個(gè) MutablePararmeterList 可以看作是 Call.parameters 的適配器),然后往里加入了一個(gè)整型參數(shù) 42,然后再調(diào)用 Call 方法把請(qǐng)求發(fā)送到服務(wù)器端。至此我們可以明白 parameters 的作用是讓我們聲明 rpc 的時(shí)候,不再需要詳細(xì)定義相應(yīng)的參數(shù)和返回值類(lèi)型了,統(tǒng)一寫(xiě)成:
view plaincopy to clipboardprint?rpc XXXX(RpcMessage)returns(RpcMessage);
即可,唯一需要變化的是用真正的方法名替換掉 XXXX。而 repeated Parameter parameters 中 repeated 的作用是為了傳入復(fù)合參數(shù),比如按常規(guī)傳入 protobuf 官方示例中的 message Person 參數(shù)的話,可能在這里是這樣的:
view plaincopy to clipboardprint?parameters.Add().SetString(name);
parameters.Add().SetInt(id);
parameters.Add().SetString(email);
不過(guò)如果有定義 message Person 的話,也可以這樣:
view plaincopy to clipboardprint?parameters.Add().SetProto(person);
可見(jiàn)各種方案都有利弊,獲得了 rpc 聲明的簡(jiǎn)潔,就需要犧牲代碼的簡(jiǎn)潔為代價(jià)。雖然說(shuō)作者的思路的確是如同天馬行空般開(kāi)闊,但如果是我的話,我不會(huì)采用這種方案,換作你呢,又會(huì)如何?
Call.expects_result 字段是告訴服務(wù)器端要不要把結(jié)果(包括是否出錯(cuò))返回給客戶(hù)端,很好理解。不過(guò) Result.call_result 是 optional,而不是 repeated,讓我覺(jué)得怪怪地,難道只準(zhǔn)多個(gè)參數(shù),不許多個(gè)返回值?
server1
server1 出自國(guó)人之手,是一個(gè)利用了 Boost 的 a c++ network server/client framework,它的作者 xiliu tang 是我的前同事。server1 的代碼還是非常簡(jiǎn)明的,先來(lái)看一下基礎(chǔ)格式:
http://code.google.com/p/server1/source/browse/trunk/server/meta.proto ,全文如下:
view plaincopy to clipboardprint?package ProtobufLineFormat;
message MetaData {
enum Type {
REQUEST = 1;
RESPONSE = 2;
};
required Type type = 1;
required uint64 identify = 2;
// the request should bring the response identify.
optional uint64 response_identify = 3;
required bytes content = 4;
};
很簡(jiǎn)單,只有一個(gè) message MetaData?對(duì)的。感覺(jué)上跟 protobuf-rpc 差不多,兩個(gè)不同:一是 MetaData 帶了一個(gè) Type,用來(lái)標(biāo)明它是請(qǐng)求還是響應(yīng);還有一個(gè)是 MetaData 使用了無(wú)符號(hào) 64 位整型作為 ID。使用 type 字段我個(gè)人感覺(jué)比 repeated/optional 的方式比起來(lái)有點(diǎn)沒(méi)有充分利用到 protobuf 特性的感覺(jué),不過(guò)相當(dāng)?shù)厍逦髁?。還有就是 response_identify 我專(zhuān)門(mén)在 GTalk 上問(wèn)過(guò)作者,他說(shuō)記不起為什么要加這個(gè)字段了……囧。我的看法是這個(gè)字段是不必要的。嗯,這個(gè)設(shè)計(jì)真的很簡(jiǎn)潔,不過(guò),我不喜歡 Meta 這個(gè)命名。
(###)