RCF远程调用框架
介紹
RCF(遠(yuǎn)程調(diào)用框架)是一個(gè)C ++ IPC框架,提供了一種在C ++程序中實(shí)現(xiàn)進(jìn)程間通信的簡(jiǎn)單而一致的方法。它基于強(qiáng)類型的客戶端/服務(wù)器接口的概念,這是基于IDL的中間件(如CORBA和DCOM)的用戶熟悉的概念。然而,通過僅適用于C ++,RCF可以利用C ++特定的語言特性,允許以更簡(jiǎn)單和更少的混亂方式來制定進(jìn)程間調(diào)用。
RCF通過支持壓縮(zlib)和多個(gè)傳輸(TCP,UDP,Windows命名管道,UNIX本地域套接字)提供了大量IPC消息傳遞范例(單獨(dú)批量,單獨(dú)批量,請(qǐng)求/響應(yīng),發(fā)布/訂閱)加密和認(rèn)證技術(shù)的數(shù)量(Kerberos,NTLM,Schannel,OpenSSL)。您可以在各種IPC方案中使用RCF,從簡(jiǎn)單的父子進(jìn)程通信到大規(guī)模分布式系統(tǒng)。最重要的是,RCF是100%標(biāo)準(zhǔn)的C ++,并且將在任何具有C ++編譯器的平臺(tái)上運(yùn)行。
RCF?網(wǎng)站上提供RCF版本和文檔。本文簡(jiǎn)要介紹了RCF。
基本
我們將從一個(gè)簡(jiǎn)單的回顯服務(wù)器和客戶端開始。我們希望服務(wù)器向客戶端公開接受字符串的函數(shù),并返回相同的字符串。使用RCF,服務(wù)器代碼變?yōu)?#xff1a;
隱藏???復(fù)制代碼#include <RCF/Idl.hpp>
#include <RCF/RcfServer.hpp>
#include <RCF/TcpEndpoint.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 &s){return s;}
};int main()
{Echo echo;RCF::RcfServer server(RCF::TcpEndpoint(50001));server.bind<I_Echo>(echo);server.startInThisThread();return 0;
} ...和客戶端代碼變成:
隱藏???復(fù)制代碼#include <RCF/Idl.hpp>
#include <RCF/TcpEndpoint.hpp>
RCF_BEGIN(I_Echo, "I_Echo")RCF_METHOD_R1(std::string, echo, const std::string &)
RCF_END(I_Echo)int main()
{RcfClient<I_Echo> echoClient(RCF::TcpEndpoint("localhost", 50001));std::string s = echoClient.echo(RCF::Twoway, "what's up");return 0;
} I_Echo是由RCF_BEGIN/?RCF_METHOD/?RCF_END宏定義的RCF接口。這些宏對(duì)應(yīng)于CORBA中的IDL定義,但是在這種情況下,接口定義被放置在C ++源代碼中,并且不需要單獨(dú)的編譯步驟,就像IDL接口一樣。該接口只包含在服務(wù)器和客戶端的源代碼中,并與程序的其余部分一起編譯。
RCF::Twoway客戶端存根調(diào)用中的參數(shù)是一個(gè)標(biāo)志,告訴RCF進(jìn)行雙向客戶端調(diào)用;?客戶端發(fā)送請(qǐng)求,等待響應(yīng),如果在可配置的持續(xù)時(shí)間內(nèi)沒有收到請(qǐng)求,則會(huì)拋出異常。另一個(gè)選擇是使用RCF::Oneway;?發(fā)送請(qǐng)求,但服務(wù)器不發(fā)送響應(yīng),客戶端存根調(diào)用將立即將控制權(quán)返回給用戶。如果省略了方向參數(shù),RCF::Twoway則默認(rèn)使用。
客戶端存根不以任何方式同步,并且一次只能由單個(gè)線程訪問。但是,服務(wù)器本質(zhì)上是多線程的,盡管在上面的示例中,它已經(jīng)被寫為單線程進(jìn)程。RcfServer::startInThisThread()劫持調(diào)用線程并將其轉(zhuǎn)換為服務(wù)器的工作線程。
我們也可以調(diào)用RcfServer::start(),然后自動(dòng)創(chuàng)建驅(qū)動(dòng)服務(wù)器所需的線程。RcfServer::start()啟動(dòng)服務(wù)器線程后立即返回。如果我們這樣做,我們需要為主線程設(shè)置一個(gè)等待循環(huán),以便它不會(huì)離開main(),關(guān)閉整個(gè)進(jìn)程。
我們可以重寫我們的客戶端/服務(wù)器對(duì)來改用UDP協(xié)議。這一次,我們會(huì)讓服務(wù)器和客戶端都駐留在同一個(gè)進(jìn)程中,但是在不同的線程中:
隱藏???收縮????復(fù)制代碼#include <RCF/Idl.hpp>
#include <RCF/RcfServer.hpp>
#include <RCF/UdpEndpoint.hpp>
#ifndef RCF_USE_BOOST_THREADS
#error Need to build with RCF_USE_BOOST_THREADS
#endif
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 &s){return s;}
};int main()
{Echo echo;RCF::RcfServer server(RCF::UdpEndpoint(50001));server.bind<I_Echo>(echo);server.start();RcfClient<I_Echo> echoClient(RCF::UdpEndpoint("127.0.0.1", 50001));std::string s = echoClient.echo(RCF::Twoway, "what's up");server.stop(); // Would happen anyway as server object goes out of scope.return 0;
} UDP當(dāng)然與TCP顯著不同。TCP提供可靠的有序傳送的網(wǎng)絡(luò)數(shù)據(jù)包,而UDP根本不保證發(fā)送的數(shù)據(jù)包的順序或數(shù)據(jù)包是否甚至到達(dá)。在一個(gè)環(huán)回連接上,就像上面的例子中一樣,由于數(shù)據(jù)包不會(huì)受到真實(shí)網(wǎng)絡(luò)的變幻莫測(cè),所以可以通過UDP使用雙向語義來避免。但是,一般來說,您只想使用UDP發(fā)送單向呼叫。
接口
界面定義宏的功能與上一代RCF?完全一樣。的RCF_BEGIN()宏開始具有給定名稱和運(yùn)行時(shí)描述的接口定義,并且RCF_END()結(jié)束該接口定義。在它們之間,最多可以有25個(gè)RCF_METHOD_xx()宏來定義接口的成員方法。
RCF_METHOD_xx()宏中的最后兩個(gè)字母表示參數(shù)的數(shù)量以及返回類型是否為void。例如,RCF_METHOD_V3用于定義具有三個(gè)參數(shù)和void返回值RCF_METHOD_R2的方法,同時(shí)定義了一個(gè)帶有兩個(gè)參數(shù)的方法和一個(gè)非void返回值。
這些宏的最終結(jié)果是定義RcfClient<type>類,type接口的名稱在哪里。然后,該類直接由客戶端作為客戶端存根直接使用,并由服務(wù)器作為服務(wù)器存根間接使用。可以在任何命名空間中定義RCF接口:
namespace A
{namespace B{RCF_BEGIN(I_X, "I_X")RCF_METHOD_V0(void, func1)RCF_METHOD_R5(int, func2, int, int, int, int, int)RCF_METHOD_R0(std::auto_ptr<std::string>, func3)RCF_METHOD_V2(void, func4,const boost::shared_ptr<std::string> &,boost::shared_ptr<std::string> &)// ..RCF_END(I_X)}
}int main()
{A::B::RcfClient<A::B::I_X> client;// orA::B::I_X::RcfClient client;// ...} 服務(wù)器綁定
在服務(wù)器端,接口需要綁定到一個(gè)具體的實(shí)現(xiàn)。這是通過模板RcfServer::bind()功能完成的。存在適應(yīng)各種內(nèi)存管理習(xí)語的幾種變體。以下調(diào)用都完成了很多相同的事情,一個(gè)Echo對(duì)象綁定到I_Echo接口:
{// Bind to an object...Echo echo;server.bind<I_Echo>(echo);// or to a std::auto_ptr<>...std::auto_ptr<Echo> echoAutoPtr(new Echo());server.bind<I_Echo>(echoAutoPtr);// or to a boost::shared_ptr<>...boost::shared_ptr<Echo> echoPtr(new Echo());server.bind<I_Echo>(echoPtr);// or to a boost::weak_ptr<>...boost::weak_ptr<Echo> echoWeakPtr(echoPtr);server.bind<I_Echo>(echoWeakPtr);
} 默認(rèn)情況下,該綁定可通過接口名稱向客戶端發(fā)送。服務(wù)器還可以通過同一個(gè)接口暴露幾個(gè)對(duì)象,但在這種情況下,它需要顯式設(shè)置綁定名稱:
隱藏???復(fù)制代碼{RcfServer server(endpoint);// Bind first object.Echo echo1;server.bind<I_Echo>(echo1, "Echo1");// Bind second object.Echo echo2;server.bind<I_Echo>(echo2, "Echo2");server.start();RcfClient<I_Echo> echoClient(endpoint);echoClient.getClientStub().setServerBindingName("Echo1");std::cout << echoClient.echo("this was echoed by the echo1 object");echoClient.getClientStub().setServerBindingName("Echo2");std::cout << echoClient.echo("this was echoed by the echo2 object");
} 整編
RCF遵循C ++約定,當(dāng)涉及到確定哪些方向參數(shù)被封送時(shí)。特別地,接口方法的所有參數(shù)都是in參數(shù),所有非常量引用參數(shù)都是inout參數(shù),返回值是一個(gè)out參數(shù)。目前,沒有任何規(guī)定在IDL定義的in/?out/?inout限定符中重寫這些約定。
不是C ++中的所有內(nèi)容都可以安全地封送,這對(duì)接口方法的參數(shù)類型有一些限制。相反,指針和引用被允許作為參數(shù);?不允許對(duì)指針的引用作為參數(shù);?指針和引用不允許作為返回值。
這意味著如果一個(gè)接口方法需要返回一個(gè)指針 - 例如一個(gè)多態(tài)指針 - 那么返回類型需要是一個(gè)智能指針,例如std::auto_ptr<>或boost::shared_ptr<>。或者,其中一個(gè)參數(shù)可能是對(duì)智能指針的非常量引用。
序列化
echo示例只是序列化一個(gè)std::string對(duì)象,但是可以在使用的序列化系統(tǒng)的限制內(nèi)幾乎發(fā)送任何C ++類或結(jié)構(gòu)。RCF有自己的序列化框架,簡(jiǎn)稱為序列化框架(SF),但它也支持Boost.Serialization框架,Boost庫的一部分。
一般來說,有必要為被封送的類包含序列化代碼。如果std::vector<>接口中有參數(shù),則需要包含<SF / vector.hpp>或<boost / serialization / vector.hpp>(或兩者),對(duì)于其他STL和Boost類,也需要包含參數(shù)。
要在RCF接口中使用您自己的類作為參數(shù),您需要定義自定義序列化函數(shù)。在大多數(shù)情況下,這很簡(jiǎn)單:
隱藏???收縮????復(fù)制代碼#include <boost/serialization/string.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <SF/string.hpp>
#include <SF/map.hpp>
#include <SF/vector.hpp>
struct X
{int myInteger;std::string myString;std::map<std::string,std::map<int,std::vector<int> > > myMap;
};// This serialization function will work as is, with both SF and B.S.
template<typename Archive>void serialize(Archive &ar, X &x)
{ar & x.myInteger & x.myString & x.myMap;
}// If you need to distinguish between SF and B.S. serialization,
// specialize the SF serialization function:
//void serialize(SF::Archive &ar, X &x)
//{
// ar & myInteger & myString & myMap;
//} 序列化可以很快變成一個(gè)復(fù)雜的事情,特別是在處理多態(tài)對(duì)象指針和指針周期時(shí)。SF和Boost.Serialization都處理這些情況,但是以不同的方式,并且對(duì)于兩者都可能需要為每個(gè)序列化系統(tǒng)編寫單獨(dú)的序列化代碼。以下是使用SF和Boost.Serialization兩者發(fā)送多態(tài)對(duì)象的示例:
隱藏???收縮????復(fù)制代碼class Base
{// Some members here.// ...
};typedef boost::shared_ptr<Base> BasePtr;class Derived1 : public Base
{// Some members here.// ...
};class Derived2 : public Base
{// Some members here.// ...
};template<typename Archive>void serialize(Archive &ar, Base &base, const unsigned int)
{// ...
}template<typename Archive>
void serialize(Archive &ar, Derived1 &derived1, const unsigned int)
{// Valid for both SF and B.S.serializeParent<Base>(derived1);// ...
}template<typename Archive>
void serialize(Archive &ar, Derived2 &derived2, const unsigned int)
{// Valid for both SF and B.S.serializeParent<Base>(derived1);// ...
}// Boost type registration, needed on both server and client.
BOOST_CLASS_EXPORT_GUID(Derived1, "Derived1")
BOOST_CLASS_EXPORT_GUID(Derived2, "Derived2")RCF_BEGIN(I_PolymorphicArgTest, "")RCF_METHOD_R1(std::string, typeOf, BasePtr)
RCF_END(I_PolymorphicArgTest)class PolymorphicArgTest
{
public:std::string typeOf(BasePtr basePtr){return typeid(*basePtr).name();}
};{// SF type registration, needed on both server and client.SF::registerType<Derived1>("Derived1");SF::registerType<Derived2>("Derived2");RcfClient<I_PolymorphicArgTest> client(endpoint);// SF serialization (default).client.getClientStub().setSerializationProtocol(RCF::SfBinary);std::string typeBase = client.typeOf( BasePtr(new Base()) );std::string typeDerived1 = client.typeOf( BasePtr(new Derived1()) );std::string typeDerived2 = client.typeOf( BasePtr(new Derived2()) );// Boost serialization.client.getClientStub().setSerializationProtocol(RCF::BsBinary);typeDerived2 = client.typeOf( BasePtr(new Derived2()) );
} 遺產(chǎn)
RCF接口現(xiàn)在支持多重繼承。接口不僅可以互相繼承,還可以從標(biāo)準(zhǔn)的C ++類繼承。接口中的方法通過它們的分派ID和它們所屬的接口的名稱的組合來標(biāo)識(shí)。此信息足以使服務(wù)器將傳入的客戶端調(diào)用映射到服務(wù)器綁定上的正確功能。下面的例子演示了接口繼承:
隱藏???收縮????復(fù)制代碼RCF_BEGIN(I_A, "I_A")RCF_METHOD_V0(void, func1)
RCF_END(I_Base)RCF_BEGIN(I_B, "I_B")RCF_METHOD_V0(void, func2)
RCF_END(I_Base)// Derives from I_A.
RCF_BEGIN_INHERITED(I_C, "I_C", I_A)RCF_METHOD_V0(void, func3)
RCF_END(I_Base)// Derives from I_A and I_B.
RCF_BEGIN_INHERITED_2(I_D, "I_D", I_A, I_B)RCF_METHOD_V0(void, func4)
RCF_END(I_Base)// Derives from abstract base class I_E.
RCF_BEGIN_INHERITED(I_F, "I_F", I_E)RCF_METHOD_V0(void, func5)
RCF_END(I_Base){RcfClient<I_C> clientC(endpoint);clientC.func3();clientC.func1();RcfClient<I_D> clientD(endpoint);clientD.func4();clientD.func2();clientD.func1();
} 過濾器
RCF支持通過一個(gè)過濾器概念來開箱即用的消息的壓縮和加密。過濾器應(yīng)用于服務(wù)器端和客戶端,并且可以應(yīng)用于傳輸層 - 例如,將SSL過濾器應(yīng)用于像TCP這樣的面向流的傳輸,或應(yīng)用于單個(gè)消息有效載荷,例如壓縮發(fā)送到面向分組的傳輸(如UDP)的消息。第一種情況我們稱之為傳輸過濾器,第二種情況是一個(gè)消息過濾器。
運(yùn)輸過濾器
在服務(wù)器 - 客戶端會(huì)話上安裝傳輸過濾器的過程由客戶端發(fā)起。客戶端查詢服務(wù)器以確定服務(wù)器是否支持給定的過濾器。如果服務(wù)器執(zhí)行,則過濾器安裝在傳輸?shù)膬啥?#xff0c;并且通信恢復(fù)。
查詢服務(wù)器和安裝過濾器的過程由客戶端存根處理。客戶端調(diào)用該ClientStub::requestTransportFilters()功能,如果與服務(wù)器協(xié)商成功,則過濾器序列然后處于活動(dòng)狀態(tài),并應(yīng)用于所有后續(xù)遠(yuǎn)程調(diào)用。
傳輸過濾器可以是雙向的,這意味著在過濾器上的單個(gè)讀取或?qū)懭胝?qǐng)求可能導(dǎo)致在連接上進(jìn)行多個(gè)讀取和寫入請(qǐng)求。例如,通過加密過濾器發(fā)送的第一個(gè)消息將啟動(dòng)涉及多個(gè)下游讀取和寫入操作的某種握手。
郵件過濾器
消息過濾器不需要代表服務(wù)器或客戶端進(jìn)行任何協(xié)商。如果客戶端存根通過一系列消息過濾器ClientStub::setMessageFilters(),則消息將通過給定的過濾器傳遞。編碼消息將以描述已使用哪些過濾器的數(shù)據(jù)為前綴,從而允許服務(wù)器對(duì)消息進(jìn)行解碼。如果服務(wù)器無法識(shí)別過濾器,則會(huì)將異常傳回客戶端。
RCF自帶的幾個(gè)過濾器:兩個(gè)用于壓縮,基于Zlib,兩個(gè)用于基于OpenSSL和Schannel的?SSL加密,以及兩個(gè)基于Windows的Kerberos和NTLM協(xié)議過濾器。這些過濾器也可以相互鏈接以創(chuàng)建過濾器序列。
加密過濾器只能用作傳輸過濾器,因?yàn)榧用芎徒饷苓^程需要雙向握手。壓縮過濾器可以用作傳輸或消息過濾器,但是通過非流傳輸?shù)膫鬏?#xff08;如UDP),僅使用無狀態(tài)壓縮過濾器才有意義。
一個(gè)例子:
隱藏???收縮????復(fù)制代碼{// Compression of payload.RcfClient<I_X> client(endpoint);client.getClientStub().setMessageFilters( RCF::FilterPtr(new RCF::ZlibStatelessCompressionFilter() ) );// Encryption of transport.std::string certFile = "client.pem";std::string certFilePwd = "client_password";client.getClientStub().requestTransportFilters( RCF::FilterPtr(new RCF::OpenSslEncryptionFilter(certFile, certFilePwd)) ) );// Multiple chained transport filters - compression followed by encryption.std::vector<RCF::FilterPtr> transportFilters;transportFilters.push_back( RCF::FilterPtr(new RCF::ZlibStatefulCompressionFilter()));transportFilters.push_back( RCF::FilterPtr(new RCF::OpenSslEncryptionFilter(certFile, certFilePwd)) ) );client.getClientStub().requestTransportFilters(transportFilters);// Multiple chained payload filters - double compression.std::vector<RCF::FilterPtr> payloadFilters;payloadFilters.push_back( RCF::FilterPtr(new RCF::ZlibStatefulCompressionFilter()));payloadFilters.push_back( RCF::FilterPtr(new RCF::ZlibStatefulCompressionFilter()));client.getClientStub().setMessageFilters(payloadFilters);
}{std::string certFile = "server.pem";std::string certFilePwd = "server_password";// FilterService service enables the server to load the filters it needs.RCF::FilterServicePtr filterServicePtr( new RCF::FilterService );filterServicePtr->addFilterFactory( RCF::FilterFactoryPtr(new RCF::ZlibStatelessCompressionFilterFactory) );filterServicePtr->addFilterFactory( RCF::FilterFactoryPtr(new RCF::ZlibStatefulCompressionFilterFactory) );filterServicePtr->addFilterFactory( RCF::FilterFactoryPtr(new RCF::OpenSslEncryptionFilterFactory(certFile, certFilePwd)) );RCF::RcfServer server(endpoint);server.addService(filterServicePtr);server.start();
} 遠(yuǎn)程對(duì)象
RcfServer該類允許用戶將類的單個(gè)實(shí)例公開到遠(yuǎn)程客戶端,但是它不會(huì)為遠(yuǎn)程客戶端在服務(wù)器上創(chuàng)建任何對(duì)象提供任何條件。這個(gè)功能是ObjectFactoryService服務(wù)的一部分。一旦將ObjectFactoryService服務(wù)安裝到服務(wù)器中,客戶端可以通過該ClientStub::createRemoteObject()功能創(chuàng)建與服務(wù)配置為允許的盡可能多的對(duì)象。
該ObjectFactoryService服務(wù)實(shí)現(xiàn)垃圾收集策略,從而最終刪除不再使用的對(duì)象(即,沒有活動(dòng)的客戶端會(huì)話,并且在可配置的持續(xù)時(shí)間內(nèi)未被訪問)。
{// Allow max 50 objects to be created.unsigned int numberOfTokens = 50;// Delete objects after 60 s, when no clients are connected to them.unsigned int objectTimeoutS = 60;// Create object factory service.RCF::ObjectFactoryServicePtr ofsPtr(new RCF::ObjectFactoryService(numberOfTokens, objectTimeoutS) );// Allow clients to create and access Echo objects, through I_Echo.ofsPtr->bind<I_Echo, Echo>();RCF::RcfServer server(endpoint);server.addService(ofsPtr);server.start();
}{RcfClient<I_Echo> client1(endpoint);bool ok = client1.getClientStub().createRemoteObject();// client1 can now be used to make calls// to a newly created object on the server.RcfClient<I_Echo> client2(endpoint);client2.getClientStub().setToken( client1.getClientStub().getToken() );// client1 and client2 will now be making calls to the same object} 會(huì)話對(duì)象
創(chuàng)建的對(duì)象由ObjectFactoryService令牌標(biāo)識(shí),并且可以由指定該特定令牌的任何客戶端訪問。所以一旦創(chuàng)建,這樣一個(gè)對(duì)象可能被許多客戶端訪問。但是,客戶端想要?jiǎng)?chuàng)建只能由特定客戶端訪問的對(duì)象是很常見的。在RCF中,這樣的對(duì)象稱為會(huì)話對(duì)象,由SessionObjectFactoryService以下方式創(chuàng)建:
{// Create session object factory service.RCF::SessionObjectFactoryServicePtr sofsPtr(new RCF::SessionObjectFactoryService() );// Allow clients to create and access Echo objects, through I_Echo.sofsPtr->bind<I_Echo, Echo>();RCF::RcfServer server(endpoint);server.addService(sofsPtr);server.start();
}{RcfClient<I_Echo> client1(endpoint);bool ok = client1.getClientStub().createRemoteSessionObject();// client1 can now make calls to its// own private Echo instance on the server.RcfClient<I_Echo> client2(endpoint);ok = client2.getClientStub().createRemoteSessionObject();// client1 and client2 will now be making calls// to their own session specific Echo instances.// When the clients close their connections, the server// will immediately delete the associated session objects.// ...} 發(fā)布/訂閱
發(fā)布/訂閱模式是眾所周知的分布式編程模式。一個(gè)進(jìn)程起著發(fā)布者的作用,并將定期的信息包發(fā)送給一組訂閱者。訂閱者呼叫發(fā)布商,并請(qǐng)求訂閱發(fā)布商發(fā)布的數(shù)據(jù)。
對(duì)于諸如UDP的分組轉(zhuǎn)發(fā)傳輸,在現(xiàn)有的RCF原語之上構(gòu)建該功能是比較直接的。對(duì)于面向流的傳輸,特別是TCP,RCF提供了一些額外的功能來實(shí)現(xiàn)發(fā)布/訂閱功能。用戶呼叫的連接被反轉(zhuǎn),然后被發(fā)布商用于發(fā)布。
這個(gè)功能被雙重PublishingService和SubscriptionService服務(wù)所包含。以下示例說明如何使用這些服務(wù):
RCF_BEGIN(I_Notify, "I_Notify")RCF_METHOD_V1(void, func1, int)RCF_METHOD_V2(void, func2, std::string, std::string)
RCF_END(I_Notify){RCF::RcfServer publishingServer(endpoint);RCF::PublishingServicePtr publishingServicePtr(new RCF::PublishingService() );publishingServer.addService(publishingServicePtr);publishingServer.start();// Start accepting subscription requests for I_Notify.publishingServicePtr->beginPublish<I_Notify>();// Call func1() on all subscribers.publishingServicePtr->publish<I_Notify>().func1(1);// Call func2(std::string, std::string) on all subscribers.publishingServicePtr->publish<I_Notify>().func2("one", "two");// Stop publishing I_Notify and disconnect all subscribers.publishingServicePtr->endPublish<I_Notify>();publishingServer.stop();
}{RCF::RcfServer subscribingServer(endpoint);RCF::SubscriptionServicePtr subscriptionServicePtr(new RCF::SubscriptionService() );subscribingServer.addService( subscriptionServicePtr );subscribingServer.start();Notify notify;subscriptionServicePtr->beginSubscribe<I_Notify>(notify,RCF::TcpEndpoint(ip, port));// notify.func1() and notify.func2() will// now be remotely called by the publisher.// ...subscriptionServicePtr->endSubscribe<I_Notify>(notify);
} 可擴(kuò)展性
RcfServer服務(wù)
該RcfServer課程通過服務(wù)理念適應(yīng)第三方擴(kuò)展。當(dāng)服務(wù)器啟動(dòng)和停止時(shí),服務(wù)將被通知。此外,服務(wù)器可以在服務(wù)器運(yùn)行時(shí)從服務(wù)器中動(dòng)態(tài)添加和刪除。典型的服務(wù)可以將對(duì)象綁定到服務(wù)器上的接口,并且還可以請(qǐng)求服務(wù)器產(chǎn)生一個(gè)線程(或產(chǎn)生自己的線程)來進(jìn)行某種定期活動(dòng)。
服務(wù)器傳輸實(shí)現(xiàn)為服務(wù)。因此,可以具有服務(wù)于單個(gè)RcfServer對(duì)象的多個(gè)傳送。有些服務(wù)可用:
ObjectFactoryService:允許客戶端在服務(wù)器上創(chuàng)建對(duì)象FilterService:允許服務(wù)器根據(jù)客戶端請(qǐng)求動(dòng)態(tài)加載過濾器PublishingService:啟用在服務(wù)器上的發(fā)布功能SubscriptionService:啟用服務(wù)器上的訂閱功能
可移植性
編譯器
RCF已經(jīng)針對(duì)大量編譯器進(jìn)行了測(cè)試,其中包括Microsoft Visual C ++(6.0版本),Borland C ++(5.6版)和GCC(2.95版)。有關(guān)完整列表,請(qǐng)參閱“?RCF用戶指南”。
平臺(tái)
RCF的TCP服務(wù)器實(shí)現(xiàn)現(xiàn)在基于Win32 I / O完成端口,這種技術(shù)限于Windows 2000及更高版本。TCP客戶端實(shí)現(xiàn)和UDP服務(wù)器/客戶端實(shí)現(xiàn)基于BSD套接字,應(yīng)該是廣泛的便攜式。在非Windows平臺(tái)上,也可選擇在Windows上,RCF利用Boost.Asio庫來實(shí)現(xiàn)TCP服務(wù)器。
建造
一般來說,要使用RCF構(gòu)建應(yīng)用程序,您需要在應(yīng)用程序的源代碼中包含src / RCF / RCF.cpp文件。您還需要Boost庫的頭文件;?自1.33.0以來的任何版本都可以。
有幾個(gè)預(yù)處理器符號(hào)可用于控制RCF的哪些部分被編譯。這些符號(hào)需要在全局范圍內(nèi)定義,即它們應(yīng)該放在項(xiàng)目設(shè)置中,而不是在源代碼中定義/未定義。
RCF_USE_BOOST_THREADS:利用Boost.Thread庫進(jìn)行互斥和線程生成功能。如果沒有定義,RCF將使用自己的內(nèi)部線程庫。RCF_USE_BOOST_ASIO:利用Boost.Asio網(wǎng)絡(luò)庫。在非Windows平臺(tái)上需要服務(wù)器端代碼。RCF_USE_ZLIB:編譯支持Zlib壓縮。RCF_USE_OPENSSL:編譯支持OpenSSL加密。RCF_USE_BOOST_SERIALIZATION:編譯支持Boost.Serialization庫。RCF_USE_SF_SERIALIZATION:編譯支持RCF的內(nèi)置序列化框架。如果既不定義RCF_USE_BOOST_SERIALIZATION也不RCF_USE_SF_SERIALIZATION定義自動(dòng)定義。RCF_NO_AUTO_INIT_DEINIT:禁用RCF的自動(dòng)初始化/去初始化設(shè)施。如果定義,用戶將必須明確地調(diào)用RCF::init()并RCF::deinit()在適當(dāng)?shù)臅r(shí)間。特別地,當(dāng)將RCF編譯為DLL以避免過早初始化時(shí),這是必要的。
所有第三方構(gòu)建依賴項(xiàng)(Boost.Threads,Boost.Serialization,Zlib,OpenSSL)都是可選的。構(gòu)建這些庫的說明超出了本文的范圍,但是如果您在構(gòu)建Boost庫時(shí)遇到問題,則可以選擇繞過Boost的構(gòu)建實(shí)用程序bjam,而只需將相應(yīng)的CPP文件編譯到應(yīng)用程序中即可。
例如,要使用Boost.Threads庫,您可以在項(xiàng)目中的boost_root / libs / thread / src中包含CPP文件。然后,定義boost_root / boost / thread / detail / config.hpp中的一個(gè)符號(hào)(可能是適當(dāng)?shù)?/span>BOOST_THREAD_USE_LIB)。
測(cè)試
下載的/ test目錄中有一套全面的測(cè)試,所有這些測(cè)試都應(yīng)該編譯并運(yùn)行而不會(huì)出現(xiàn)故障。可以使用Boost.Build實(shí)用程序自動(dòng)構(gòu)建和運(yùn)行測(cè)試,或者手動(dòng)構(gòu)建和運(yùn)行。測(cè)試運(yùn)行的功能比我在這里提到的功能更多,可能作為用戶信息來源很有用。
歷史
- 2005-12-23 - 版本0.1發(fā)布
- 2006-04-06 - 版本0.2發(fā)布
RCF現(xiàn)在在Linux和Solaris以及Windows上編譯和運(yùn)行。服務(wù)器和客戶端可以分布在多個(gè)平臺(tái)上,并且仍然無縫通信。
該短耳網(wǎng)絡(luò)庫是在非Windows平臺(tái)上使用RCF的先決條件。下載Asio,確保編譯器可以使用Asio頭,并確保
RCF_USE_ASIO在編譯RCF時(shí)定義了預(yù)處理器符號(hào)。Asio需要Boost的1.33.0或更新版本,您可能希望定義BOOST_DATE_TIME_NO_LIB何時(shí)使用它,以避免不必要的Boost依賴關(guān)系。RCF 0.2已經(jīng)在以下編譯器上進(jìn)行了編譯和測(cè)試:
- GCC 3.2(Windows上的MinGW)
- GCC 3.3(Linux)
- GCC 3.4(Solaris)
- Borland C ++ 5.6
- Metrowerks CodeWarrior 9.2
- Microsoft Visual C ++ 7.1
- Microsoft Visual C ++ 8.0
在這個(gè)論壇上報(bào)道的各種錯(cuò)誤也已經(jīng)修復(fù)。
對(duì)任何正在等待這個(gè)發(fā)布的人道歉...我原本計(jì)劃在幾個(gè)月前發(fā)布,但忙碌的工作時(shí)間表(和一些固執(zhí)的測(cè)試用例)干預(yù)了。抱歉!
- 2006-07-30 - 版本0.3發(fā)布
- 現(xiàn)在,RCF對(duì)Asio的支持已經(jīng)由David Bergman從0.3.5升級(jí)到0.3.7版本。謝謝大衛(wèi)!
- 對(duì)Asio 0.3.5的支持已經(jīng)下降。
- 預(yù)處理器符號(hào)
RCF_USE_ASIO現(xiàn)在命名RCF_USE_BOOST_ASIO。 - 這個(gè)論壇上報(bào)道的雜項(xiàng)問題也已經(jīng)解決。
- 2006-09-19 - 版本0.4發(fā)布
- 64位兼容性:RCF現(xiàn)在可在64位Solaris,Linux和Windows平臺(tái)上編譯和運(yùn)行。
- 的快速序列化
std::vector<T>,其中T是原語(char,int等)。 - 對(duì)于那些使用RCF在32位和64位系統(tǒng)之間通信的用戶,可以避免使用類似于RCF接口
long或類似std::size_tRCF接口的類型,從而避免由32位和64位系統(tǒng)之間的大小差異引起的序列化錯(cuò)誤。使用的升壓一個(gè)typedef!而非(boost::int32_t,boost::uint32_t,boost::int64_t,boost::uint64_t)。 - 最后,感謝不倫瑞克技術(shù)大學(xué)的Freudiger,為64位的Linux機(jī)器借了我一個(gè)帳號(hào)!
- 2007-07-11 - 版本0.9c發(fā)布
- RCF 0.9c,RCF 1.0的預(yù)發(fā)行版本現(xiàn)在可從Google Code的下載部分獲得。在發(fā)展一年多的時(shí)間里,RCF 0.9c是RCF 0.4的重大改組和升級(jí)。已經(jīng)將其作為一個(gè)主要的商業(yè)ECM平臺(tái)的網(wǎng)絡(luò)后端,已經(jīng)被徹底的放縱了。
- 使用RCF 0.4的應(yīng)用程序在升級(jí)到RCF 0.9c方面的難度相對(duì)較小。如果您將應(yīng)用程序移植到0.9c有任何問題,請(qǐng)隨時(shí)通過本論壇或通過電子郵件與我聯(lián)系。我會(huì)很樂意幫助你。
- RCF 0.9c功能包括:
- 零拷貝,零堆分配核心,實(shí)現(xiàn)快速和可擴(kuò)展的性能。
- SSPI過濾器,用于Windows平臺(tái)上的透明Kerberos和NTLM身份驗(yàn)證和加密。
- OpenSSL過濾器,用于透明的SSL認(rèn)證和加密。
- 服務(wù)器端多線程
- 服務(wù)器端會(huì)話對(duì)象。
- 內(nèi)置運(yùn)行時(shí)版本控制,用于向后和向前運(yùn)行時(shí)兼容。
- 強(qiáng)大的發(fā)布/訂閱功能。
- 支持遺留編譯器,特別是Visual C ++ 6,Borland C ++ Builder 6和GCC 2.95。
- 支持64位編譯器。
- 2007-08-23 - 文章內(nèi)容更新
- 2008-04-28 - 版本0.9d-P1發(fā)布
- RCF 0.9d-P1是RCF-0.9d的預(yù)覽。它已經(jīng)在Windows上完全測(cè)試,與Visual C ++編譯器的范圍(6.0,7.1,8.0,9.0)完全相同。RCF 0.9d版本將包括對(duì)Linux和Solaris的全面支持,以及用戶指南形式的大量文檔。
- 從Google代碼網(wǎng)站的下載頁面獲取。
- RCF 0.9d功能包括:
- Win32命名管道傳輸實(shí)現(xiàn)(
RCF::Win32NamedPipeEndpoint)。 - Boost.Thread不再需要。
- UDP組播和廣播。
- SF序列化
boost::tuple,boost::variant和boost::any。 - 支持從DLL導(dǎo)出RCF。
- 兼容最新的Boost(1.35.0)和Boost.Asio(0.3.8+)版本。
- 與RCF 0.9c保證電線兼容。
- Win32命名管道傳輸實(shí)現(xiàn)(
- 2008-07-20 - 文章內(nèi)容更新
- 2008-07-20 - 版本0.9d發(fā)布
- RCF 0.9d現(xiàn)在可供下載。
- 作為0.9d版本的一部分,“?RCF用戶指南”現(xiàn)在可以在線獲得。
- 一如以往,歡迎提問和意見!
- 2008-10-22 - 版本1.0發(fā)布
- RCF 1.0現(xiàn)在可以下載。
- RCF 1.0功能包括:
- 支持更多的編譯器(Intel C ++ 9和10.1 for Windows,GCC 4.3)
- 支持更多的平臺(tái)(FreeBSD和OS X)。
- 兼容Boost 1.36.0和1.37.0。
- 支持使用UNIX域套接字作為transport(
RCF::UnixLocalEndpoint)。 - 更新“?RCF用戶指南”。
- 感謝Duane Murphy提供原始的OS X端口。
- 2009-07-10 - 版本1.1發(fā)布
- RCF 1.1現(xiàn)在可以下載。
- RCF 1.1功能包括:
- Ping功能添加到
RCF::ClientStub。 - 服務(wù)器到客戶端pingback,用于在長(zhǎng)時(shí)間運(yùn)行的呼叫(
RCF::PingBackService)中維護(hù)連接。 - 服務(wù)器到客戶端的回調(diào)。
- 動(dòng)態(tài)線程池增長(zhǎng)和收縮,以適應(yīng)客戶端負(fù)載。用戶級(jí)代碼不再需要調(diào)用
ThreadManager::notifyBusy()。 - 所有運(yùn)輸?shù)倪M(jìn)度回調(diào)。
- 基于Schannel的傳輸過濾器,用于Windows平臺(tái)上的SSL加密。
- 針對(duì)Boost版本測(cè)試,最高1.39.0。
- 支持
__attribute__(visibility())使用GCC 4.x構(gòu)建共享庫時(shí)。 - 內(nèi)存使用優(yōu)化。
- Ping功能添加到
- Visual C ++ 6用戶需要
auto_ptr<>::release()在Visual C ++ 6 STL實(shí)現(xiàn)中應(yīng)用修復(fù)。 - 通常情況下,RCF用戶指南中的詳細(xì)信息。
- 2010-02-15 - 版本1.2發(fā)布
- RCF 1.2現(xiàn)在可供下載。
- RCF 1.2功能包括:
- 支持Google的協(xié)議緩沖區(qū)(文檔在這里)。
- 支持批量的單向呼叫(此處的文檔)。
- 針對(duì)Boost版本測(cè)試,高達(dá)1.42.0。
- 如果您從早期版本的RCF升級(jí)到RCF 1.2,則需要注意以下幾個(gè)突破性更改:
- SF序列化功能現(xiàn)在具有不同的簽名。冗余版本參數(shù)已被刪除,因此對(duì)于外部序列化功能,簽名現(xiàn)在為“?
void serialize(SF::Archive &, SomeType & t)”。對(duì)于內(nèi)部序列化功能,簽名現(xiàn)在為“?void SomeType::serialize(SF::Archive &)”。 - 全局
serializeParent()函數(shù)已被移入SF命名空間。 - 該
RCF::Exception::getError()功能已重命名為getErrorId()。
- SF序列化功能現(xiàn)在具有不同的簽名。冗余版本參數(shù)已被刪除,因此對(duì)于外部序列化功能,簽名現(xiàn)在為“?
- “?RCF用戶指南”中提供了發(fā)行說明。
- 2011-01-06 - 版本1.3發(fā)布
- RCF 1.3現(xiàn)在可供下載。
- RCF 1.3功能包括:
- 支持IPv6。
- 基于IP的訪問規(guī)則,授予或拒絕訪問基于IP的服務(wù)器。
- 請(qǐng)求和響應(yīng)標(biāo)頭中的用戶數(shù)據(jù)字段。
- 在同一線程池上運(yùn)行多個(gè)服務(wù)器傳輸。
- 應(yīng)用對(duì)象的服務(wù)器端緩存。
- 默認(rèn)最大郵件長(zhǎng)度從10KB更改為1MB。
- RCF界面中最多的方法從35增加到100。
- 擴(kuò)展自動(dòng)版本協(xié)商存檔版本以及運(yùn)行時(shí)版本。
- SF序列化
- 支持
tr1容器和tr1智能指針。 - 支持
boost::intrusive_ptr<>。 - 序列化
std::wstring改變,使用UTF-8。
- 支持
- 針對(duì)Boost版本測(cè)試高達(dá)1.45.0。
- “?RCF用戶指南”中提供了發(fā)行說明。
- 2011-10-25 - 版本1.3.1發(fā)布
- RCF 1.3.1現(xiàn)在可供下載。
- RCF 1.3.1是RCF 1.3的錯(cuò)誤修復(fù)版本。修正錯(cuò)誤:
- 在RCF方法簽名中使用signed char時(shí)修復(fù)編譯器錯(cuò)誤。
- 使用時(shí)修復(fù)性能問題
RCF::SspiFilter。現(xiàn)在,將多個(gè)小消息塊合并成一個(gè)較大的塊,以提高網(wǎng)絡(luò)性能。 - 改進(jìn)的SF序列化性能。只有
typeid()在必要時(shí)才打電話 - 減少SF檔案大小。使用單個(gè)字節(jié)而不是4個(gè)字節(jié)對(duì)小整數(shù)進(jìn)行編碼。
- 在使用基于Boost.Asio的傳輸?shù)亩嗑€程線程池時(shí),修復(fù)了CPU使用率過高。
- 修正為
boost::any序列化。空的boost::any實(shí)例導(dǎo)致拋出異常。 - 修正使用Windows?
MsgWaitForMultipleObjects()功能輪詢網(wǎng)絡(luò)連接時(shí)客戶端超時(shí)邏輯的錯(cuò)誤。 - 在
RcfServer運(yùn)行時(shí)不能再添加或刪除服務(wù)。 - 在封送邏輯中固定潛在的空指針崩潰。
- 重命名變量命名
signals和slots為了不干擾QT預(yù)處理器。 - 修復(fù)了在OSX上導(dǎo)致編譯器警告的預(yù)處理器重新定義。
- “?RCF用戶指南”中提供了發(fā)行說明。
- Web論壇現(xiàn)在可用于與RCF相關(guān)的問題和意見。
許可證
請(qǐng)注意:每個(gè)下載的代碼是完全獨(dú)立的。文章和代碼的許可證如下:
- 該文章根據(jù)“代碼項(xiàng)目開放許可證(CPOL)”獲得許可。
- RCF 0.4根據(jù)麻省理工學(xué)院的許可證獲得許可。
- RCF 0.9c及更高版本根據(jù)GPL許可證獲得許可。
總結(jié)
- 上一篇: 公主连结超得是什么意思?
- 下一篇: android AIDL IPC深入分