过滤器(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_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);
}