概述
客户端的slice-to-c++映射
slice标识符会映射到相同的c++标识符,如果一个slice的标识符与某个c++关键字一样,那么对应的c++
标识符会加上前缀 _cpp_
命名空间的映射是一样的
接口映射:
要调用一个远地操作,要调用本地类实例的成员函数,这个实例代表的是远地的对象。
这使得映射变得容易,使用也直观。
举例:
interface Simple {
void op();
};
例如上述slice接口,映射到c++
namespace IceProxy {
class Simple : public virtual IceProxy::Ice::Object {
public:
void op();
void op(const Ice::Context &);
// ...
};
}
typedef IceInternal::ProxyHandle<IceProxy::Simple> SimplePrx;
如上所示,上述slice生成一个类simple和一个类代理SimplePrx
c++程序会一般直接使用这个代理句柄,而不会使用这个类
操作的映射
对于接口的每一个操作,代理类都有一个对应的同名成员函数,要调用某一个操作,
要通过代理句柄调用它。
例如,对于接口:
module Filesystem {
interface Node {
nonmutating string name();
};
// ...
};
生成如下代理:
namespace IceProxy {
namespace Filesystem {
class Node : virtual public IceProxy::Ice::Object {
public:
std::string name();
// ...
};
typedef IceInternal::ProxyHandle<Node> NodePrx;
// ...
}
// ...
}
最终的调用方法是:
NodePrx node = ...; //initiallize proxy
string name = node->name(); // Get name via rpc
操作分为普通的,idempotent和nonmutating操作
idempotent表示安全的对数据进行多次修改
nonmutating表示对数据不做任何修改
传递参数:
slice的出入参数通过值和const引用
传出参数通过引用
类映射:
例如如下类:
class TimeOfDay {
short hour; // 0 - 23
short minute; // 0 - 59
short second; // 0 -59
string format(); // Return time as hh:mm:ss
};
最终生成的代码:
class TimeOfDay : virtual public Ice::Object {
public:
Ice::Short hour;
Ice::Short minute;
Ice::Short second;
virtual std::string format() = 0;
virtual bool ice_isA(const std::string &);
virtual const std::string & ice_id();
static const std::string & ice_staticId();
static const Ice::ObjectFactoryPtr & ice_factory();
};
typedef IceInternal::Handle<TimeOfDay> TimeOfDayPtr;
类操作:
在生成的类中,类上的操作被映射到纯虚函数,这意味着,如果类
函数操作,必须从生成的类派生一个类
例如:
class TimeOfDayI : virtual public TimeOfDay {
public:
virtual std::string format() {
std::ostringstream s;
s << setw(2) << setfill('0') << hour;
s << setw(2) << setfill('0') << minute;
s << setw(2) << setfill('0') << second;
return s.c_str();
}
};
类工厂:
对于接口
interface Time {
TimeOfDay get();
};
需要告知ice要怎么实例化TimeOfDay,就需要一个工厂,
我们必须向Ice run time 提供一个工厂,这个工厂知道TimeOfDay 抽象类
有一个TimeOfDayI 具体实现。Ice::Communicator 接口为我们提供了所需的操作
具体的代码如下:
Ice::CommunicatorPtr ic = ...;
ic->addObjectFactory(new ObjectFactory, "::TimeOfDay");
类的智能指针:
对于Slice类<class-name>,编译器会生成叫作<class-name>Ptr 的C++ 智能
指针。
服务端的slice-to-c++映射
Ice run time 的主要进入点是本地接口 Ice::Communicator来表示。
第一步要调用 Ice::initialize初始化,同理在离开main函数的时候,需要调用destory
上述的ICE初始化方法可以用Ice::Application类来替代
示例代码
int main(int argc,char* argv[])
{
int status = 0;
Ice::CommunicatorPtr ic;
try{
ic = Ice::initialize(argc.argv);
}
catch(const Ice::Exception &e)
{
cerr<< e <<endl;
status = 1;
}
...
}
Ice::Service类
骨架类:
在客户端,接口映射到代理类,在服务器端,接口映射到骨架类
module Filesystem{
interface Node
{
nonmutating string name();
};
};
编译器为这个接口生成这样的定义:
namespace Filesystem
{
class Node : virtual public Ice::Object {
public:
virtual std::string name(const Ice::Current & =
Ice::Current()) const = 0;
// ...
};
}
• 和客户端一样,Slice 模块映射到名字相同的C++ 名字空间,所以骨架类
• 定义会放在名字空间Filesystem 中。
• 骨架类的名字与Slice 接口的名字(Node)相同。
• 对于Slice 接口中的每个操作,骨架类都有一个对应的纯虚成员函数。
• 骨架类是抽象基类,因为它的成员函数是纯虚函数。
• 骨架类继承自Ice::Object (这个类形成了Ice 对象层次的根)。
Servant类
要给Ice对象提供实现,必须创建servant类,继承对应的骨架类,
例如,为Node接口创建servant
class NodeI : public virtual Filesystem::Node
{
public:
NodeI(const std::string &);
virtual std::string name(const Ice::Current &)const;
private:
std::string _name;
}
参数传递所遵循的规则和客户端一样
对象的体现:
要实现Ice对象的体现,需要遵循如下步骤:
1.实例化servant类
2. 为这个servant 所体现的Ice 对象创建标识。
3. 向Ice run time 告知这个servant 的存在。
4. 把这个对象的代理传给客户,以让客户访问它。
实例化servant
NodePtr servant = new NodeI("Fred");
或者:
typedef IceUtil::Handle<NodeI> NodeIPtr;
NodeIPtr servant = new NodeI("Fred");
创建标识:
每一个ICE对象都需要一个标识,在使用同一个对象的所有
servant中,该标识是唯一的。
Module Ice
{
struct Identity
{
string name;
string category;
}
}
示例:
Ice::Identity id;
id.name = "Fred";
激活Servant
只要显式的把servant告知对象适配器之后,Ice run time 才会知道这个servant的存在
要激活servant,要调用对象适配器的add操作,
_adapter->add(servant,id);
举例:
void activeServant(const string & name)
{
NodePtr servant = new NodeI(name); //Recount = 1;
Ice::Identity id;
id.name = name;
_adapter->add(servant,id);
}
用UUID做标识符
用uuid做标识符可以保证唯一性
_adapter->addWithUUID(servant);
创建代理:
一旦激活Ice的servant,服务器就可以处理针对这个对象的请求了。
但是,只有拥有了对象的代理,客户才能访问该对象。
对象适配器含有创建代理所需的全部详细信息,寻址信息和协议信息,
还有对象标识。Ice run time 提供几种创建代理的途径,一经创建,
可以将代理当做返回值或者操作调用的out参数传给客户。
代理与Servant激活
有两种方法获取代理 直连和通过icegrid
对象适配器的add和addwithuuid servant激活操作会返回对应的
Ice对象的一个代理,示例:
typedef IceUtil::Handle<NodeI> NodeIPtr;
NodeIPtr servant = new NodeI(name);
NodeIPtr proxy = NodeIPtr::uncheckedCast(_adapter->addWithUUID(servant));
直接代理创建:
Ice::Identity id;
id.name = IceUtil::generateUUID();
objectPrx o = _adapter->createProxy(id);
Ice属性与配置
需要设置 ICE_CONFIG环境变量
c++线程与并发
Ice线程库提供了一下与线程有关的抽象:
1)互斥体
2)递归互斥体
3)读写递归互斥体
4)监控器
5)一个线程抽象,容许你创建、控制、销毁线程
互斥体:
IceUtil::Mutex类和IceUtil::staticMutex提供了简单的非递归互斥机制
递归体:
RecMutex;
读写互斥体
readlock和writeLock
定时锁:
为读写锁提供一个超时操作
监控器:
Monitor是临界保护区的同步机制,相当于condition机制
Ice Run Time详解
Ice::Communicator监控的资源:
1)客户端线程池
2)服务端线程池
3)配置属性
4)对象工厂
5)日志记录器对象
6)统计对象
7)缺省路由器
8)缺省定位器
9)插件管理器
10)对象适配器
通信器的操作:
1)proxyToString
2)stringToProxy
这两个操作允许你把dialing转换成串化表示,或者进行反向转换
1)createObjectAdapter
2) createObjectAdapterWithEndpoints
这两个操作创建新的对象适配器,没个对象适配器都与一个或多个
传输端点关联在一起。
createObjectAdapter 从配置文件读如主机名端口号信息
而createObjectAdapterWithEndpoints需要用户自己指定
适配器状态:
适配器具有如下几个状态:
1)扣留状态:
适配器任何到来的请求都会被扣留
2)活动状态:
这种状态的适配器会接受新到来的请求
3)不活动状态:
已经处理的请求继续,但不接受新的请求
对象标识
module Ice{
struct Identity{
string name;
string category;
}
}
这个标识可以唯一的确定servants
Ice::current对象
通过访问Current对象,可以访问"正在执行的请求"和"服务器中操作的实现"等操作,
包括:
当前请求的对象适配器
当前请求的对象标识
请求的facet
正在被调用的操作的名字
成员含有的操作的调用模式(Normal,Idempotent、Nonmutating)
Servant定位器
略
Ice::Context
module Ice{
local dictionary<string,string> Context;
}
上下文就是把一个串映射带串的词典。
调用超时:
客户发出的远程调用是同步和阻塞的,也就是说客户端调用完成的
条件是服务器处理完该调用,如果想要迫使它终止,可以调用
ice_timeout操作
举例来说
Filesystem::FilePrx myFile = ...;
FileSystem::FilePrx timeoutFile
= FileSystem::FilePrx::uncheckedCast(
myFile->ice_timeout(5000));
try {
Lines text = timeoutFile->read(); // Read with timeout
} catch(const Ice::TimeoutException &) {
cerr << "invocation timed out" << endl;
}
Lines text = myFile->read(); // Read without timeout
如果通过timeoutFile调用read函数,5秒后没有反馈就是收到异常
单向调用:
ICEPack
IcePack提供了若干基本的服务,可以简化复杂的分布式应用和部署
1)定位服务器,用于定位对象和保证位置的透明性
2)服务器激活和监控服务,用于管理服务器进程
3)服务器部署机制
4)IcePack注册表,用于管理部署在特定域中的应用的所有相关信息
5)IcePack节点,用于激活和监控服务器的进程
绑定:
绑定是把代理和它的servant连接起来的过程
有两种绑定方法,直接绑定和间接绑定
直接绑定:
调用createObjectAdapterWithEndpoints
或createObjectAdapter
间接绑定:
客户不需要为代理指定端点信息,代理端点可以由
Ice run time 动态确定
部署:
应用部署包含配置文件的创建和安装,icebox的初始化,
编写脚本处理启动和关闭流程。
Ice定位器设施
IceStorm
IceStorm,用于实现应用的 发布/订阅
收集器-----> IceStorm ------>各个监视器
消息:
IceStrom的消息是强类型,IceStorm的消息递送使用的是推模式,轮询模式不支持
主题:
应用要通过订阅某个主题(topic)来表明自己有兴趣接收某些消息
IceStorm服务器能够订阅任意数量的主题,这些主题是动态创建的,通过
唯一的名字来区分。
单向语义:
IceStorm具有单向语义,因此发布者无法接收起订阅者的答复
成本:
成本是与消息和链接相关联在一起的,当你在某个主题上发布消息的时候,
主题会拿与它每个链接相关联的成本与消息成本进行比较,并且只在那些成本
等于或超过消息成本的链接上传播该消息。
服务质量:
Qos IceStrom订阅者可以在订阅时指定Qos参数,IceStorm目前只支持reliablity
设定oneway,一收到消息就发出去,减少了消息因为IceStrom故障而丢失的可能性
设定batch会把消息放进队列里面,其存放时间可以配置,这增加了消息因为故障而
丢失的可能性,但是使开销更小
持久:
IceStorm用于一个数据,里面维护的是关于其 主题和链接信息
订阅者出错:
因为IceStorm 消息是采用单向语义递送的, IceStorm 只能检测到连接或
超时错误。如果在把消息递送给订阅者的过程中, IceStorm 遇到这样的错
误,该订阅者就会立刻被解除与该消息对应的主题的订阅。
慢速的订阅者也可能会造成问题。一旦消息发布, IceStorm 会立刻尝试
递送它们:IceStorm 发布者对象可能会一收到消息就嵌套地调用主题的订
阅者。因此,如果订阅者消费消息的速度没有发布的速度快,它就可能造
成IceStorm 中的线程数不断增加。如果线程数到达了线程池的最大尺寸,
那么就不再能发布新消息了。
IceStorm接口综述:
TopicManager:
TopicManager是一个单体对象,充当的是Topic对象的工厂和仓库,接口类型
如下:
module IceStorm
{
dictonary<string,topic*> TopicDict;
}
exception TopicExists{
string name;
}
exception NoSuchTopic {
string name;
};
interface TopicManager {
Topic* create(string name) throws TopicExists;
nonmutating Topic* retrieve(string name) throws NoSuchTopic;
nonmutating TopicDict retrieveAll();
};
Topic:
Topic接口表示一个主题,用于配置链接/管理订阅者
module IceStorm{
struct LinkInfo
{
Topic* theTopic;
string name;
int cost;
}
};
sequence<LinInfo> LinkInfoSeq;
dictionary<string,string> Qos;
exception LinkExists{
string name;
}
interface Topic
{
nonmutating string getName();
nonmutating Object* getPublisher();
void subscribe(QoS theQos,Object* subscriber);
idempotent void unsubscribe(Object* subscriber);
idempotent void link(Topic* linkTo,int cost)throws LinkExists;
idempotent void unlink(Topic* linkTo) throws NoSuchLink;
nonmutating LinkInfoSeq getLinkInfoSeq();
void destroy();
}
};
};
实现发布订阅需要的语句:
struct Measurement{
string tower; //tower id;
float windSpeed; //knots;
short windDirection; //degrees
float temperature; //degrees Celsius
}
interface Monitor
{
void report(Measurement m);
};
收集器的实现:
1.获取TopicManager的一个代理,这是IceStorm的主要对象
2.获取Weather主题的一个代理--如果主题不存在,就创建它,否则就获取已有
主题的代理。
3.获取Weather主题的'发布者'的代理,用于发布消息,因此会被窄化成主题接口(Monitor)
4.收集帮报告观测数据
Ice::objectPrx obj = communicator->stringToProxy("IceStorm/TopicManager:tcp -p 9999");
IceStorm::TopicManagerPrx topicManager = IceStorm::TopicManagerPrx::checkedCast(obj);//获取TopicManager的一个代理,这是IceStorm的主要对象
IceStorm::TopicPrx topic; //
try{
topic = topicManager->retrieve("Weather");
}
catch(const IceStorm::NoSuchTopic&){
topic = topicManager->creat("Weather"); //获取主题代理
}
Ice::ObjectPrx pub = topic->getPublisher(); //获取一个发布者
if (!pub->ice_isDatagram())
pub = pub->ice_oneway();
MonitorPrx monitor = MonitorPrx::uncheckedCast(pub); //获取发布者代理并设置QOs参数
while(true)
{
Measurement m = getMeasurement(); //收集到发布的数据并report
monitor->report(m);
}
}
监视器:
class MonitorI : virtual public Monitor
{
public:
virtual void report(const Measurement& m,const Ice::Current&)
{
cout<<"Measurement report"<<endl;
...
}
} //这个可以理解为被调用的函数
Ice::objectPrx obj = communicator->stringToProxy("IceStorm/TopicManager:tcp -p 9999");
IceStorm::TopicManagerPrx topicManager = IceStorm::TopicManagerPrx::checkedCast(obj); //
最后
以上就是个性柜子为你收集整理的ICE使用总结的全部内容,希望文章能够帮你解决ICE使用总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复