RMI for C++ 是一個專為 C++ 語言提供的遠程方法調用框架,與 CORBA 不同的是,CORBA 適合不同的編程語言之間進行互操作,而 RMI for C++ 專為 C++ 涉及,因此效率更高,速度更快,開發也便捷。工程如圖:
工程需要用到第三方庫boost(已放到源碼包中),Boost庫是一個經過千錘百煉、可移植、提供源代碼的C++庫,作為標准庫的後備,是C++標准化進程的發動機之一。
Boost庫由C++標准委員會庫工作組成員發起,在C++社區中影響甚大,其成員已近2000人。 Boost庫為我們帶來了最新、最酷、最實用的技術,是不折不扣的“准”標准庫。
程序是使用CORBA規范調用C++程序,在源碼中直接使用預處理器指定接口以及封裝進程參數,當然需要使用Boost庫序列化本地C++程序框架。
echo服務器
實例源碼:
[cpp]
#include <RCF/RCF.hpp>
RCF_BEGIN(I_Echo, "I_Echo")
RCF_METHOD_R1(std::string, echo, const std::string &);
RCF_END(I_Echo);
class Echo
{
public:
std::string echo(const std::string &msg) { return msg; }
};
int main()
{
int port = 50001;
RCF::RcfServer server(port);
server.bind<I_Echo, Echo>();
server.start();
return 0;
}
echo客戶端
實例源碼:
[cpp]
#include <RCF/RCF.hpp>
RCF_BEGIN(I_Echo, "I_Echo")
RCF_METHOD_R1(std::string, echo, const std::string &);
RCF_END(I_Echo);
int main()
{
std::cout << RcfClient<I_Echo>("localhost",
50001).echo("my message");
return 0;
}
Boost.Serialization庫,用於序列化的參數和返回值。它具有標准的類型和容器自動進行,很容易擴展到用戶定義的類。它也使我們能夠序列化指針,多態指針和妥善處理單個對象的多個指針。
基本用法
使用這個框架有三個基本步驟:
使用RCF_xxx宏來定義接口。
使用的的暴露RcfServer類實現該接口的對象。
使用RcfClient <>類公開的對象的服務器上調用方法。
接口定義宏的使用方法如下:
[cpp]
RCF_BEGIN( type, type_id )
// ...
RCF_METHOD_xx( return_type, name, ....):
// ...
RCF_END( type )
type是為接口的標識符,TYPE_ID是一個字符串,給出一個運行時的接口的描述。
一旦我們定義了一個接口使用RCF_xxx宏,我們就可以啟動服務器,並綁定到具體對象的接口:
[cpp]
{
// create the server and tell it which port to listen on
RCF::RcfServer server(port);
// Interface is the identifer of the interface we're exporting,
// Object is a type that implements that interface
// one object for each client
server.bind<Interface, Object>();
// ... or one object shared by all clients
Object object;
server.bind<Interface>(object);
// tell the server to start listening for connections
server.start();
// ...
// the server will shut down automatically as it goes out of scope
}
該對象是靜態綁定到相應的接口,也沒有必要為對象從一個接口類派生的情況一樣,為傳統的動態多態性。取而代之的是,編譯器在編譯的時候,這不僅是更有效的解決了接口,但也允許更靈活的語義。
服務器可以同時處理多個客戶端,即使在單線程模式下,並且可以在任何時候停止。服務器所公開的對象的生命周期來確定當前連接到給定的對象的數目,一旦有沒有更多的活的對象的連接,超時被設置,並當它過期時,該對象被刪除。
為了使客戶端調用,我們實例化相應的RcfClient <>模板,並通過服務器的IP地址和端口號的構造函數。當第一個遠程方法調用,客戶端,然後嘗試連接到服務器,給定對象的查詢,調用遠程對象的請求的成員函數,然後返回遠程的返回值。
[cpp]
// define the interface
RCF_BEGIN(Interface, "Interface")
RCF_METHOD_R2(int, add, int, int);
RCF_END(Interface);
// ...
{
std::string ip = "localhost";
int port = 50001;
RcfClient<Interface> client(ip, port);
// connect and call the add function
int sum = client.add(1,1);
// connection closed as we exit scope
}
如果出現任何異常,在服務器端調用請求的對象時,一個異常的類型RCF :: RemoteException的傳播回客戶端和拋出。如果出現任何異常,在其他地方,例如在服務器端,而序列化的參數,那麼服務器將強行關閉連接時,客戶端會拋出一個異常。
RCF自動處理的參數類型,包括int、 double、std::string、STL容器、指針、引用、boost::shared_ptr、std::auto_ptr等等。
在CORBA中,標記的參數中有in、 out、inout,根據它們把參數進行封送處理。按照以下約定:
[cpp]
Value: in
Pointer: in
Const reference: in
Nonconst reference: inout
Nonconst reference to pointer: out
要使用用戶定義的類型作為參數或返回值,需要一些額外的序列化代碼(Boost.Serialization),如下。
[cpp]
struct MyStruct
{
int a;
int b;
int c;
double d;
std::string s;
std::map <std::string, std::vector<std::string> > m;
template<typename Archive>
void serialize(Archive &archive, unsigned int version)
{
ar & a & b & c & d & s & m;
}
};
RCF_BEGIN(MyInterface, "MyInterface")
RCF_METHOD_R1(MyStruct, myfunc, const MyStruct &);
RCF_END(MyInterface);