RCF - C ++的进程间通信
介紹
RCF(遠程調(diào)用框架)是一個C ++ IPC框架,提供了一種在C ++程序中實現(xiàn)進程間通信的簡單而一致的方法。它基于強類型的客戶端/服務(wù)器接口的概念,這是基于IDL的中間件(如CORBA和DCOM)的用戶熟悉的概念。然而,通過僅適用于C ++,RCF可以利用C ++特定的語言特性,允許以更簡單和更少的混亂方式來制定進程間調(diào)用。
RCF通過支持壓縮(zlib)和多個傳輸(TCP,UDP,Windows命名管道,UNIX本地域套接字)提供了大量IPC消息傳遞范例(單獨批量,單獨批量,請求/響應(yīng),發(fā)布/訂閱)加密和認(rèn)證技術(shù)的數(shù)量(Kerberos,NTLM,Schannel,OpenSSL)。您可以在各種IPC方案中使用RCF,從簡單的父子進程通信到大規(guī)模分布式系統(tǒng)。最重要的是,RCF是100%標(biāo)準(zhǔn)的C ++,并且將在任何具有C ++編譯器的平臺上運行。
RCF?網(wǎng)站上提供RCF版本和文檔。本文簡要介紹了RCF。
基本
我們將從一個簡單的回顯服務(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接口。這些宏對應(yīng)于CORBA中的IDL定義,但是在這種情況下,接口定義被放置在C ++源代碼中,并且不需要單獨的編譯步驟,就像IDL接口一樣。該接口只包含在服務(wù)器和客戶端的源代碼中,并與程序的其余部分一起編譯。
RCF::Twoway客戶端存根調(diào)用中的參數(shù)是一個標(biāo)志,告訴RCF進行雙向客戶端調(diào)用;?客戶端發(fā)送請求,等待響應(yīng),如果在可配置的持續(xù)時間內(nèi)沒有收到請求,則會拋出異常。另一個選擇是使用RCF::Oneway;?發(fā)送請求,但服務(wù)器不發(fā)送響應(yīng),客戶端存根調(diào)用將立即將控制權(quán)返回給用戶。如果省略了方向參數(shù),RCF::Twoway則默認(rèn)使用。
客戶端存根不以任何方式同步,并且一次只能由單個線程訪問。但是,服務(wù)器本質(zhì)上是多線程的,盡管在上面的示例中,它已經(jīng)被寫為單線程進程。RcfServer::startInThisThread()劫持調(diào)用線程并將其轉(zhuǎn)換為服務(wù)器的工作線程。
我們也可以調(diào)用RcfServer::start(),然后自動創(chuàng)建驅(qū)動服務(wù)器所需的線程。RcfServer::start()啟動服務(wù)器線程后立即返回。如果我們這樣做,我們需要為主線程設(shè)置一個等待循環(huán),以便它不會離開main(),關(guān)閉整個進程。
我們可以重寫我們的客戶端/服務(wù)器對來改用UDP協(xié)議。這一次,我們會讓服務(wù)器和客戶端都駐留在同一個進程中,但是在不同的線程中:
隱藏???收縮????復(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ù)包是否甚至到達。在一個環(huán)回連接上,就像上面的例子中一樣,由于數(shù)據(jù)包不會受到真實網(wǎng)絡(luò)的變幻莫測,所以可以通過UDP使用雙向語義來避免。但是,一般來說,您只想使用UDP發(fā)送單向呼叫。
接口
界面定義宏的功能與上一代RCF?完全一樣。的RCF_BEGIN()宏開始具有給定名稱和運行時描述的接口定義,并且RCF_END()結(jié)束該接口定義。在它們之間,最多可以有25個RCF_METHOD_xx()宏來定義接口的成員方法。
RCF_METHOD_xx()宏中的最后兩個字母表示參數(shù)的數(shù)量以及返回類型是否為void。例如,RCF_METHOD_V3用于定義具有三個參數(shù)和void返回值RCF_METHOD_R2的方法,同時定義了一個帶有兩個參數(shù)的方法和一個非void返回值。
這些宏的最終結(jié)果是定義RcfClient<type>類,type接口的名稱在哪里。然后,該類直接由客戶端作為客戶端存根直接使用,并由服務(wù)器作為服務(wù)器存根間接使用。可以在任何命名空間中定義RCF接口:
隱藏???復(fù)制代碼 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ù)器端,接口需要綁定到一個具體的實現(xiàn)。這是通過模板RcfServer::bind()功能完成的。存在適應(yīng)各種內(nèi)存管理習(xí)語的幾種變體。以下調(diào)用都完成了很多相同的事情,一個Echo對象綁定到I_Echo接口:
隱藏???復(fù)制代碼 {// 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ù)器還可以通過同一個接口暴露幾個對象,但在這種情況下,它需要顯式設(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ù)都是in參數(shù),所有非常量引用參數(shù)都是inout參數(shù),返回值是一個out參數(shù)。目前,沒有任何規(guī)定在IDL定義的in/?out/?inout限定符中重寫這些約定。
不是C ++中的所有內(nèi)容都可以安全地封送,這對接口方法的參數(shù)類型有一些限制。相反,指針和引用被允許作為參數(shù);?不允許對指針的引用作為參數(shù);?指針和引用不允許作為返回值。
這意味著如果一個接口方法需要返回一個指針 - 例如一個多態(tài)指針 - 那么返回類型需要是一個智能指針,例如std::auto_ptr<>或boost::shared_ptr<>。或者,其中一個參數(shù)可能是對智能指針的非常量引用。
序列化
echo示例只是序列化一個std::string對象,但是可以在使用的序列化系統(tǒng)的限制內(nèi)幾乎發(fā)送任何C ++類或結(jié)構(gòu)。RCF有自己的序列化框架,簡稱為序列化框架(SF),但它也支持Boost.Serialization框架,Boost庫的一部分。
一般來說,有必要為被封送的類包含序列化代碼。如果std::vector<>接口中有參數(shù),則需要包含<SF / vector.hpp>或<boost / serialization / vector.hpp>(或兩者),對于其他STL和Boost類,也需要包含參數(shù)。
要在RCF接口中使用您自己的類作為參數(shù),您需要定義自定義序列化函數(shù)。在大多數(shù)情況下,這很簡單:
隱藏???收縮????復(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; //}序列化可以很快變成一個復(fù)雜的事情,特別是在處理多態(tài)對象指針和指針周期時。SF和Boost.Serialization都處理這些情況,但是以不同的方式,并且對于兩者都可能需要為每個序列化系統(tǒng)編寫單獨的序列化代碼。以下是使用SF和Boost.Serialization兩者發(fā)送多態(tài)對象的示例:
隱藏???收縮????復(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)識。此信息足以使服務(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支持通過一個過濾器概念來開箱即用的消息的壓縮和加密。過濾器應(yīng)用于服務(wù)器端和客戶端,并且可以應(yīng)用于傳輸層 - 例如,將SSL過濾器應(yīng)用于像TCP這樣的面向流的傳輸,或應(yīng)用于單個消息有效載荷,例如壓縮發(fā)送到面向分組的傳輸(如UDP)的消息。第一種情況我們稱之為傳輸過濾器,第二種情況是一個消息過濾器。
運輸過濾器
在服務(wù)器 - 客戶端會話上安裝傳輸過濾器的過程由客戶端發(fā)起。客戶端查詢服務(wù)器以確定服務(wù)器是否支持給定的過濾器。如果服務(wù)器執(zhí)行,則過濾器安裝在傳輸?shù)膬啥?#xff0c;并且通信恢復(fù)。
查詢服務(wù)器和安裝過濾器的過程由客戶端存根處理。客戶端調(diào)用該ClientStub::requestTransportFilters()功能,如果與服務(wù)器協(xié)商成功,則過濾器序列然后處于活動狀態(tài),并應(yīng)用于所有后續(xù)遠程調(diào)用。
傳輸過濾器可以是雙向的,這意味著在過濾器上的單個讀取或?qū)懭胝埱罂赡軐?dǎo)致在連接上進行多個讀取和寫入請求。例如,通過加密過濾器發(fā)送的第一個消息將啟動涉及多個下游讀取和寫入操作的某種握手。
郵件過濾器
消息過濾器不需要代表服務(wù)器或客戶端進行任何協(xié)商。如果客戶端存根通過一系列消息過濾器ClientStub::setMessageFilters(),則消息將通過給定的過濾器傳遞。編碼消息將以描述已使用哪些過濾器的數(shù)據(jù)為前綴,從而允許服務(wù)器對消息進行解碼。如果服務(wù)器無法識別過濾器,則會將異常傳回客戶端。
RCF自帶的幾個過濾器:兩個用于壓縮,基于Zlib,兩個用于基于OpenSSL和Schannel的?SSL加密,以及兩個基于Windows的Kerberos和NTLM協(xié)議過濾器。這些過濾器也可以相互鏈接以創(chuàng)建過濾器序列。
加密過濾器只能用作傳輸過濾器,因為加密和解密過程需要雙向握手。壓縮過濾器可以用作傳輸或消息過濾器,但是通過非流傳輸?shù)膫鬏?#xff08;如UDP),僅使用無狀態(tài)壓縮過濾器才有意義。
一個例子:
隱藏???收縮????復(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(); }遠程對象
RcfServer該類允許用戶將類的單個實例公開到遠程客戶端,但是它不會為遠程客戶端在服務(wù)器上創(chuàng)建任何對象提供任何條件。這個功能是ObjectFactoryService服務(wù)的一部分。一旦將ObjectFactoryService服務(wù)安裝到服務(wù)器中,客戶端可以通過該ClientStub::createRemoteObject()功能創(chuàng)建與服務(wù)配置為允許的盡可能多的對象。
該ObjectFactoryService服務(wù)實現(xiàn)垃圾收集策略,從而最終刪除不再使用的對象(即,沒有活動的客戶端會話,并且在可配置的持續(xù)時間內(nèi)未被訪問)。
隱藏???收縮????復(fù)制代碼 {// 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}會話對象
創(chuàng)建的對象由ObjectFactoryService令牌標(biāo)識,并且可以由指定該特定令牌的任何客戶端訪問。所以一旦創(chuàng)建,這樣一個對象可能被許多客戶端訪問。但是,客戶端想要創(chuàng)建只能由特定客戶端訪問的對象是很常見的。在RCF中,這樣的對象稱為會話對象,由SessionObjectFactoryService以下方式創(chuàng)建:
隱藏???收縮????復(fù)制代碼 {// 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ā)布/訂閱模式是眾所周知的分布式編程模式。一個進程起著發(fā)布者的作用,并將定期的信息包發(fā)送給一組訂閱者。訂閱者呼叫發(fā)布商,并請求訂閱發(fā)布商發(fā)布的數(shù)據(jù)。
對于諸如UDP的分組轉(zhuǎn)發(fā)傳輸,在現(xiàn)有的RCF原語之上構(gòu)建該功能是比較直接的。對于面向流的傳輸,特別是TCP,RCF提供了一些額外的功能來實現(xiàn)發(fā)布/訂閱功能。用戶呼叫的連接被反轉(zhuǎn),然后被發(fā)布商用于發(fā)布。
這個功能被雙重PublishingService和SubscriptionService服務(wù)所包含。以下示例說明如何使用這些服務(wù):
隱藏???收縮????復(fù)制代碼 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); }可擴展性
RcfServer服務(wù)
該RcfServer課程通過服務(wù)理念適應(yīng)第三方擴展。當(dāng)服務(wù)器啟動和停止時,服務(wù)將被通知。此外,服務(wù)器可以在服務(wù)器運行時從服務(wù)器中動態(tài)添加和刪除。典型的服務(wù)可以將對象綁定到服務(wù)器上的接口,并且還可以請求服務(wù)器產(chǎn)生一個線程(或產(chǎn)生自己的線程)來進行某種定期活動。
服務(wù)器傳輸實現(xiàn)為服務(wù)。因此,可以具有服務(wù)于單個RcfServer對象的多個傳送。有些服務(wù)可用:
- ObjectFactoryService:允許客戶端在服務(wù)器上創(chuàng)建對象
- FilterService:允許服務(wù)器根據(jù)客戶端請求動態(tài)加載過濾器
- PublishingService:啟用在服務(wù)器上的發(fā)布功能
- SubscriptionService:啟用服務(wù)器上的訂閱功能
可移植性
編譯器
RCF已經(jīng)針對大量編譯器進行了測試,其中包括Microsoft Visual C ++(6.0版本),Borland C ++(5.6版)和GCC(2.95版)。有關(guān)完整列表,請參閱“?RCF用戶指南”。
平臺
RCF的TCP服務(wù)器實現(xiàn)現(xiàn)在基于Win32 I / O完成端口,這種技術(shù)限于Windows 2000及更高版本。TCP客戶端實現(xiàn)和UDP服務(wù)器/客戶端實現(xiàn)基于BSD套接字,應(yīng)該是廣泛的便攜式。在非Windows平臺上,也可選擇在Windows上,RCF利用Boost.Asio庫來實現(xiàn)TCP服務(wù)器。
建造
一般來說,要使用RCF構(gòu)建應(yīng)用程序,您需要在應(yīng)用程序的源代碼中包含src / RCF / RCF.cpp文件。您還需要Boost庫的頭文件;?自1.33.0以來的任何版本都可以。
有幾個預(yù)處理器符號可用于控制RCF的哪些部分被編譯。這些符號需要在全局范圍內(nèi)定義,即它們應(yīng)該放在項目設(shè)置中,而不是在源代碼中定義/未定義。
- RCF_USE_BOOST_THREADS:利用Boost.Thread庫進行互斥和線程生成功能。如果沒有定義,RCF將使用自己的內(nèi)部線程庫。
- RCF_USE_BOOST_ASIO:利用Boost.Asio網(wǎng)絡(luò)庫。在非Windows平臺上需要服務(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定義自動定義。
- RCF_NO_AUTO_INIT_DEINIT:禁用RCF的自動初始化/去初始化設(shè)施。如果定義,用戶將必須明確地調(diào)用RCF::init()并RCF::deinit()在適當(dāng)?shù)臅r間。特別地,當(dāng)將RCF編譯為DLL以避免過早初始化時,這是必要的。
所有第三方構(gòu)建依賴項(Boost.Threads,Boost.Serialization,Zlib,OpenSSL)都是可選的。構(gòu)建這些庫的說明超出了本文的范圍,但是如果您在構(gòu)建Boost庫時遇到問題,則可以選擇繞過Boost的構(gòu)建實用程序bjam,而只需將相應(yīng)的CPP文件編譯到應(yīng)用程序中即可。
例如,要使用Boost.Threads庫,您可以在項目中的boost_root / libs / thread / src中包含CPP文件。然后,定義boost_root / boost / thread / detail / config.hpp中的一個符號(可能是適當(dāng)?shù)?/span>BOOST_THREAD_USE_LIB)。
測試
下載的/ test目錄中有一套全面的測試,所有這些測試都應(yīng)該編譯并運行而不會出現(xiàn)故障。可以使用Boost.Build實用程序自動構(gòu)建和運行測試,或者手動構(gòu)建和運行。測試運行的功能比我在這里提到的功能更多,可能作為用戶信息來源很有用。
歷史
- 2005-12-23 - 版本0.1發(fā)布
- 2006-04-06 - 版本0.2發(fā)布
RCF現(xiàn)在在Linux和Solaris以及Windows上編譯和運行。服務(wù)器和客戶端可以分布在多個平臺上,并且仍然無縫通信。
該短耳網(wǎng)絡(luò)庫是在非Windows平臺上使用RCF的先決條件。下載Asio,確保編譯器可以使用Asio頭,并確保RCF_USE_ASIO在編譯RCF時定義了預(yù)處理器符號。Asio需要Boost的1.33.0或更新版本,您可能希望定義BOOST_DATE_TIME_NO_LIB何時使用它,以避免不必要的Boost依賴關(guān)系。
RCF 0.2已經(jīng)在以下編譯器上進行了編譯和測試:
- 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
在這個論壇上報道的各種錯誤也已經(jīng)修復(fù)。
對任何正在等待這個發(fā)布的人道歉...我原本計劃在幾個月前發(fā)布,但忙碌的工作時間表(和一些固執(zhí)的測試用例)干預(yù)了。抱歉!
- 2006-07-30 - 版本0.3發(fā)布
- 現(xiàn)在,RCF對Asio的支持已經(jīng)由David Bergman從0.3.5升級到0.3.7版本。謝謝大衛(wèi)!
- 對Asio 0.3.5的支持已經(jīng)下降。
- 預(yù)處理器符號RCF_USE_ASIO現(xiàn)在命名RCF_USE_BOOST_ASIO。
- 這個論壇上報道的雜項問題也已經(jīng)解決。
- 2006-09-19 - 版本0.4發(fā)布
- 64位兼容性:RCF現(xiàn)在可在64位Solaris,Linux和Windows平臺上編譯和運行。
- 的快速序列化std::vector<T>,其中T是原語(char,int等)。
- 對于那些使用RCF在32位和64位系統(tǒng)之間通信的用戶,可以避免使用類似于RCF接口long或類似std::size_tRCF接口的類型,從而避免由32位和64位系統(tǒng)之間的大小差異引起的序列化錯誤。使用的升壓一個typedef!而非(boost::int32_t,boost::uint32_t,boost::int64_t,boost::uint64_t)。
- 最后,感謝不倫瑞克技術(shù)大學(xué)的Freudiger,為64位的Linux機器借了我一個帳號!
- 2007-07-11 - 版本0.9c發(fā)布
- RCF 0.9c,RCF 1.0的預(yù)發(fā)行版本現(xiàn)在可從Google Code的下載部分獲得。在發(fā)展一年多的時間里,RCF 0.9c是RCF 0.4的重大改組和升級。已經(jīng)將其作為一個主要的商業(yè)ECM平臺的網(wǎng)絡(luò)后端,已經(jīng)被徹底的放縱了。
- 使用RCF 0.4的應(yīng)用程序在升級到RCF 0.9c方面的難度相對較小。如果您將應(yīng)用程序移植到0.9c有任何問題,請隨時通過本論壇或通過電子郵件與我聯(lián)系。我會很樂意幫助你。
- RCF 0.9c功能包括:
- 零拷貝,零堆分配核心,實現(xiàn)快速和可擴展的性能。
- SSPI過濾器,用于Windows平臺上的透明Kerberos和NTLM身份驗證和加密。
- OpenSSL過濾器,用于透明的SSL認(rèn)證和加密。
- 服務(wù)器端多線程
- 服務(wù)器端會話對象。
- 內(nèi)置運行時版本控制,用于向后和向前運行時兼容。
- 強大的發(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上完全測試,與Visual C ++編譯器的范圍(6.0,7.1,8.0,9.0)完全相同。RCF 0.9d版本將包括對Linux和Solaris的全面支持,以及用戶指南形式的大量文檔。
- 從Google代碼網(wǎng)站的下載頁面獲取。
- RCF 0.9d功能包括:
- Win32命名管道傳輸實現(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保證電線兼容。
- 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)
- 支持更多的平臺(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,用于在長時間運行的呼叫(RCF::PingBackService)中維護連接。
- 服務(wù)器到客戶端的回調(diào)。
- 動態(tài)線程池增長和收縮,以適應(yīng)客戶端負(fù)載。用戶級代碼不再需要調(diào)用ThreadManager::notifyBusy()。
- 所有運輸?shù)倪M度回調(diào)。
- 基于Schannel的傳輸過濾器,用于Windows平臺上的SSL加密。
- 針對Boost版本測試,最高1.39.0。
- 支持__attribute__(visibility())使用GCC 4.x構(gòu)建共享庫時。
- 內(nèi)存使用優(yōu)化。
- Visual C ++ 6用戶需要auto_ptr<>::release()在Visual C ++ 6 STL實現(xiàn)中應(yīng)用修復(fù)。
- 通常情況下,RCF用戶指南中的詳細(xì)信息。
- 2010-02-15 - 版本1.2發(fā)布
- RCF 1.2現(xiàn)在可供下載。
- RCF 1.2功能包括:
- 支持Google的協(xié)議緩沖區(qū)(文檔在這里)。
- 支持批量的單向呼叫(此處的文檔)。
- 針對Boost版本測試,高達1.42.0。
- 如果您從早期版本的RCF升級到RCF 1.2,則需要注意以下幾個突破性更改:
- SF序列化功能現(xiàn)在具有不同的簽名。冗余版本參數(shù)已被刪除,因此對于外部序列化功能,簽名現(xiàn)在為“?void serialize(SF::Archive &, SomeType & t)”。對于內(nèi)部序列化功能,簽名現(xiàn)在為“?void SomeType::serialize(SF::Archive &)”。
- 全局serializeParent()函數(shù)已被移入SF命名空間。
- 該RCF::Exception::getError()功能已重命名為getErrorId()。
- “?RCF用戶指南”中提供了發(fā)行說明。
- 2011-01-06 - 版本1.3發(fā)布
- RCF 1.3現(xiàn)在可供下載。
- RCF 1.3功能包括:
- 支持IPv6。
- 基于IP的訪問規(guī)則,授予或拒絕訪問基于IP的服務(wù)器。
- 請求和響應(yīng)標(biāo)頭中的用戶數(shù)據(jù)字段。
- 在同一線程池上運行多個服務(wù)器傳輸。
- 應(yīng)用對象的服務(wù)器端緩存。
- 默認(rèn)最大郵件長度從10KB更改為1MB。
- RCF界面中最多的方法從35增加到100。
- 擴展自動版本協(xié)商存檔版本以及運行時版本。
- SF序列化
- 支持tr1容器和tr1智能指針。
- 支持boost::intrusive_ptr<>。
- 序列化std::wstring改變,使用UTF-8。
- 針對Boost版本測試高達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的錯誤修復(fù)版本。修正錯誤:
- 在RCF方法簽名中使用signed char時修復(fù)編譯器錯誤。
- 使用時修復(fù)性能問題RCF::SspiFilter。現(xiàn)在,將多個小消息塊合并成一個較大的塊,以提高網(wǎng)絡(luò)性能。
- 改進的SF序列化性能。只有typeid()在必要時才打電話
- 減少SF檔案大小。使用單個字節(jié)而不是4個字節(jié)對小整數(shù)進行編碼。
- 在使用基于Boost.Asio的傳輸?shù)亩嗑€程線程池時,修復(fù)了CPU使用率過高。
- 修正為boost::any序列化。空的boost::any實例導(dǎo)致拋出異常。
- 修正使用Windows?MsgWaitForMultipleObjects()功能輪詢網(wǎng)絡(luò)連接時客戶端超時邏輯的錯誤。
- 在RcfServer運行時不能再添加或刪除服務(wù)。
- 在封送邏輯中固定潛在的空指針崩潰。
- 重命名變量命名signals和slots為了不干擾QT預(yù)處理器。
- 修復(fù)了在OSX上導(dǎo)致編譯器警告的預(yù)處理器重新定義。
- “?RCF用戶指南”中提供了發(fā)行說明。
- Web論壇現(xiàn)在可用于與RCF相關(guān)的問題和意見。
許可證
請注意:每個下載的代碼是完全獨立的。文章和代碼的許可證如下:
- 該文章根據(jù)“代碼項目開放許可證(CPOL)”獲得許可。
- RCF 0.4根據(jù)麻省理工學(xué)院的許可證獲得許可。
- RCF 0.9c及更高版本根據(jù)GPL許可證獲得許可。
總結(jié)
以上是生活随笔為你收集整理的RCF - C ++的进程间通信的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Sublime Less 自动编译成cs
- 下一篇: bzoj1025题解