过滤器( Filters )
RCF 通过过滤器的概念来支持对消息的压缩和加密。过滤器需要同时应用于服务器端和客户端。也可以被应用于传输层,例如应用 SSL 过滤器到向 TCP 这样基于流的传输;或者应用于独立的消息载荷,例如压缩像 UDP 这样基于包传递的消息。前者称为传输过滤器,后者称为载荷过滤器。
传输过滤器
在一个服务器 - 客户的会话中安装一个传输过滤器是由客户端发起的。客户端查询服务器端是否支持给定的过滤器,如果服务器端支持,过滤器就会同时在两端安装,然后继续通讯。
询问服务器端和安装过滤器的过程是由客户端桩自动处理的。用户只要在远程调用之前调用 ClientStub::setTransportFilters()
,客户端桩会自动询问服务器端并且安装过滤器。
传输过滤器可以用 two-way 方式的,那样的话一个读操作或者写操作都会导致下行方向的多个读写请求。 一个典型的例子就是一个 SSL 加密过滤器在任何时刻都需要发起一个握手操作,这个握手操作又会包含多个下行的读写请求。
载荷过滤器
使用载荷过滤器不需要服务器端或者客户端任何特殊的步骤。如果客户端桩通过 ClientStub::setPayloadFilters()
函数调用设置了过滤器,消息的载荷将会用设置的过滤器来传输。载荷的前面会被加入足够的数据,以便让服务器端能够解码传输用的过滤器,从而让服务器端解码传输的载荷。如果服务器端不能解码这个过滤器,服务器端将返回一个异常到客户端。
载荷过滤器必须使用 one-way 方式,也就是说一个读操作只会导致在下行方向的一个或者多个读请求(译注:传输过滤器则会导致多个读写请求),写操作也是类型的。 RCF 本身已经提供了几个过滤器:基于 Zlib 的两个压缩过滤器,还有一个基于 OpenSSL 的 SSL 加密过滤器。这些过滤器也可以被连接起来使用,从而提高过滤器序列。
OpenSSL 的加密过滤器只能用于传输过滤器,因为 SSL 的加密和解密过程需要一个 two-way 的会话,这个前面也有提到过。另一方面,有状态和无状态的压缩过滤器可以被用于传输和载荷过滤器。在像 UDP 这样非面向流的传输之上,只有用无状态的压缩过滤器才是有意义的。但是,在想 TCP 这样的传输之上,有状态好无状态压缩过滤器都是可以使用的。
一个例子:
...
{ // compression of payload RcfClient< I_X > client(endpoint); client.setPayloadFilters( RCF::FilterPtr( new RCF::ZlibStatelessCompressionFilter() ) ); // encryption of transport std::string certFile = " client.pem " ; std:: string certFilePwd = " client_password " ; client.setTransportFilters( RCF::FilterPtr( new RCF::OpenSslEncryptionFilter( RCF::SslClient, 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( RCF::SslClient, certFile, certFilePwd)) ) ); client.setTransportFilters(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.setPayloadFilters(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
类允许用户暴露( expose )一个类的单个实例给远程客户端,但也没有限制远程客户端在服务器上创建对象。远程对象创建就是 ObjectFactoryService
服务的职责。一旦在服务器端安装了 ObjectFactoryService
服务,客户端就可以通过 I_ObjectFactory
接口来创建对象,允许创建对象的个数是在服务中配置的。
ObjectFactoryService
服务还实现了一个垃圾回收机制,借此机制那些不再使用(例如没有活动的客户端会话或者在配置的持续时间内没有客户端访问)的对象最终将会被删除。请注意:目前在此服务内还没有一个安全保证机制。一个创建了的对象可以被这个服务器的所有客户端访问。
...
{ // 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 objectFactoryServicePtr( new RCF::ObjectFactoryService(numberOfTokens, objectTimeoutS) ); // allow clients to create and access Echo objects, through I_Echo objectFactoryServicePtr -> bind < I_Echo, Echo > (); RCF::RcfServer server(endpoint); server.addService(objectFactoryServicePtr); server.start(); }
...
{ RcfClient < I_Echo > client1(endpoint); bool ok = RCF::createRemoteObject < I_Echo > (client1); // client can now be used to access a newly created object on the server. RcfClient< I_Echo > client2(endpoint); client2.getClientStub().setToken( client1.getClientStub().getToken() ); // client1 and client2 will now be accessing the same object }
发布订阅( Publish/Subscribe )
发布订阅模式是分布式程序中众所周知的术语。一个进程扮演发布者的角色,定期地给订阅者发送消息包。订阅者呼叫发布者并且请求发布者发布的订阅数据。
对于像 UDP 这样面向包的传输,在已有的 RCF 原语上建立这个功能是相对简单的。对于像 TCP 这样的面向流的传输, RCF 提供了额外的特征来使能发布订阅功能。订阅者呼叫的连接被逆转,然后发布者利用这个连接来发布。
PublishingService
和 SubscriptionService
两个服务构成了这个功能。下面的例子描述了如何使用这些服务。
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 invoked by the publisher // ... subscriptionServicePtr-> endSubscribe < I_Notify > (notify); }