现在的位置: 首页 > 综合 > 正文

ICE框架组件内部实现与特点

2018年03月19日 ⁄ 综合 ⁄ 共 10832字 ⁄ 字号 评论关闭

1,Ice::Application 此类中有一个main的方法,main的方法中调用了run()函数。

ICE框架的服务配置结构:

class ResTransferServer : public Ice::Application
{
public:

    virtual int run(int argc, char* argv[])
    {
        Ice::CommunicatorPtr communicator = this->communicator(); //得到一个通信器指针
        Ice::ObjectAdapterPtr adapter = communicator->createObjectAdapter("PUSHResourceTransferSvrObjectAdapter"); //创建一个配置器指针
        Ice::PropertiesPtr properties = communicator->getProperties(); //创建一个通信器的权限
        PUSH::ResTransferPtr resTransSvr = new ResTransferI;
        adapter->add(resTransSvr, communicator->stringToIdentity(properties->getProperty("Identity"))); //增加一个适配器
        adapter->activate();//激发启动一个通信器
        communicator->waitForShutdown();  //通信器在这里等待处理数据连接
        return EXIT_SUCCESS;
    }
};

int  main(int argc, char* argv[])
{
    Ice::InitializationData initData;  //初始化ICE相关的数据;原型是 Ice::initialize 
    initData.properties = Ice::createProperties(); //创建通信器的属性接口
    initData.properties->setProperty("BuildId", std::string("Ice ") + ICE_STRING_VERSION);//设置所有者的相关属性,或者通信器的所有属性,ICE中属性的原型接口为Properties()

    PUSHResTransferServer app; //实际的服务对象
    int status = app.main(argc, argv, initData);

 //这里对象调用main的原因是公有继承Ice::Application类中的mian函数

     return status;  //返回结果传递给主线程,使系统来处理其他业务
 }

 

2,ICE框架中slice生成的类都是抽象类,我们要重新继承他实现对此类中数据及方法的实例化的类

3,在ICE的一部调用中特别注意的几点,用具体的实例来说明

具体的函数实现参数说明

 virtual void downRes_async(const PUSH::AMD_ResTransfer_downResPtr& amdPtr, const ::PUSH::Wmmp3MsgHead&, const PUSH::Wmmp3MsgDownRes& request, const
::Ice::Current& = ::Ice::Current());

 

注意:

ICE的每个方法都提供了一个Ice::Current的对象,这个对象主要是存储ICE框架中的各个骨架信息的参数类的对象。例如,adapter适配器,ctx数据内容的类对象等等。

具体结构如下:

module Ice {
    local dictionary<string, string> Context;
    enum OperationMode { Normal, \Nonmutating, \Idempotent };
    local struct Current {

        ObjectAdapter   adapter;
        Connection      con;
        Identity        id;
        string          facet;
        string          operation;
        OperationMode   mode;
        Context         ctx;
        int             requestId;
    };
};

 


4,此虚方法的实现:

 void ResTransferI::downRes_async(const PUSH::AMD_ResTransfer_downResPtr& amdPtr, const ::PUSH::Wmmp3MsgHead&,
const ::PUSH::Wmmp3MsgDownRes& request, const ::Ice::Current& current) //这里的参数是ICE框架中提供的参数用来传递
{

 amdPtr->ice_response(response); //提供回包的方法

 //Ice在每个代理方法之后,携带了一个参数Ice::Context,这个参数实际是一个Map结构。它是一种“给方法提供额外数据(与方法所代表的业务无关的)”的方式

    ::Ice::Context ctx = outcommPrx->ice_getContext();
    char range[100]= {0};
    ::sprintf(range,"bytes=%d-%d", request.offset,(int)request.blockSize + request.offset);
    ctx["url"] = httpUrl + attachinfo.file_save_name();//配网址
    ctx["method"] = "get";
    ctx["Range"] = range; //"xxx-xxx";
    ctx["outheader"] = "1";

 

}

 

 void ResTransferI::downRes_async()  //ICE的AMD异步分派方法函数组成,格式:函数名_async

5,异步调用的时候要使用回调函数意思是先把数据发送出去等有结果在在回国投来处理这个消息;

回调函数的有2个部分组成:第一个是回调方法,第二个是回调信息 

回调方法类如下:

class ResTransferCallback : public IceUtil::Shared //红色的是ICE中提供的类
    {
    public:
         void exception(const Ice::Exception& ex, const DSE::AMDCallbackCookiePtr& cookie)
         {
             cookie->getAMDCallback()->ice_exception(ex);   //捕捉异常的方法
         }

         void sent(bool sentSynchronously, const DSE::AMDCallbackCookiePtr& cookie)
         {
         }

//执行回调的方法函数,回调之后的问题是相关返回参数数据的获取,一般我们将这些信心存储在cookie类中,例如下面的DSE::AMDCallbackCookiePtr这个类就是用来保存我们需要的返回数据的。
         void downResResponse(const Ice::ByteSeq & respContent, const PUSH::HeaderMap & headers, const DSE::AMDCallbackCookiePtr&
cookie
);
    };

//将一个类转化为这个类的智能指针方法格式化,这是ICE里面提供的方法。

 typedef ::IceUtil::Handle<ResTransferCallback> ResTransferCallbackPtr;


回调信息的存储类是如下:

class AMDResTransferCallbackCookie : public ::DSE::AMDCallbackCookie//红色的是ICE的callback实现的类 
    {
    public:
        AMDResTransferCallbackCookie(const AMDCallbackPtr& amdPtr)
        :AMDCallbackCookie(amdPtr)
        {}  
  
        void setTlvs(const ::PUSH::TlvMap & tlvs)
        {
            _tlvs = tlvs;
        }
        ::PUSH::TlvMap getTlvs( )
        {
   return  _tlvs;
        }

        void setTransId(const int & TransId)
        {
            _TransId = TransId;
        }
        int getTransId()
        {
          return  _TransId;
        }

    private:
        int _TransId;
  ::PUSH::TlvMap _tlvs;
    };
    //ICE中将抽象类转化为智能指针
    typedef ::IceUtil::Handle<AMDResTransferCallbackCookie> AMDResTransferCallbackCookiePtr;

 6,ice通过cookie专递需要返回的数据存放在AMDcallbackCookie的类中,下来就是关于cookie类的智能指针转化为一般的AMDcallbackCookie类的对象

//dynamicCast(cookie);貌似是一种转化的方式
 
    AMDResTransferCallbackCookiePtr myCookie = AMDResTransferCallbackCookiePtr::dynamicCast(cookie);
    AMD_ResTransfer_downResPtr amdPtr = AMD_ResTransfer_downResPtr::dynamicCast(myCookie->getAMDCallback()); 
 //具体体现还原智能指针的方法。
    response.transId = myCookie->getTransId();

 

7,ICE的slice文件内容事项:

sequence<Fruit> FruitPlatter;  //序列话一个类型为一个vector<char>容器变量。

dictionary<long, Employee> EmployeeMap; //将一个类型设置为一个map容器来处理。

头文件只允许使用<>括号,注释使用;结构中的返回值变量要赋值;常量要使用const修饰。

基本数据类型有:int , byte, ice::ByteSeq  bool, string,short ,long,float,double ;

左边是输入参数使用:in ,右边是输出参数使用:out ;

函数类型使用: void ;

slice文件的中定义的结构中的数据成员是编译之后就会产生对应的公有数据成员,函数方法都会成为纯虚函数。

slice的事例文件://红色字体都是要注意的关键字

#include <SystemException.ice>

module TEST      //编译后是命名空间
{
    struct WmmpInfo
 {
        TlvMap tlvs; //此结构可以来自其他的slice文件
 };
    sequence WmmpInfo> MsgAppSeq; //将来会成为vector容器
   

dictionary<string, string> HeaderMap; //将来会成为map容器
    struct Header
    {
        string transID;
       byte retcode = 0xFF;
    };

 interface AppClass  //抽象类名
    {

  ["ami"] void sendStateRpt( in  Header Header, out Response respMsg ) throws DSE::SystemException;  //ami表示同步,

 ["amd", "ami"] void downUrlInfo(  in   PushRequest
reqMsg,  out Response respMsg )     throwsDSE::SystemException //amd表示异步的方式
    };
}

                                     二,ICE片段讲解

1,将数据写入ICE流中 IceInternal::BasicStream stream(IceInternal::getInstance(_communicator).get());
 stream.resize(outParams.size());    stream.i = stream.b.begin();    memcpy(stream.b.begin(), &outParams[0], outParams.size());


2,适配器包含通信器获取一个通信器智能指针
 Ice::CommunicatorPtr communicator = current.adapter->getCommunicator(); 你在任何时候都可以调用Communicator::getProperties,获得特定通信器的属性集。
例如:从当前对象中获取配置文件的参数: 这里所指的是通过ICE当前对象获取的
Ice::PropertiesPtr properties = current.adapter->getCommunicator()->getProperties();
        std::string strURL = properties->getProperty("MsgStateRptUrl");

3,定义一个代理指针通过通信器指针服务的标识符获取代理指针。
::Ice::ObjectPrx base = communicator->stringToProxy(PUSH_TDISPATCH_OUT_IDENTITY);  //communicator通信器的只能指针
ice每一个服务对象都是通过身份确认的唯一标识来找到对应的服务同时调用相关的接口。例如:通过代理获取内容参数对象方便从配置文件中取得参数:
  Ice::Context ctx = outcommPrx->ice_getContext();    Ice::PropertiesPtr properties = communicator->getProperties();
    ctx["url"] = properties->getProperty("MsgStateRptUrl");

4,在创建通信器前对参数进行设置setProperty 操作把某个属性设成指定的值(只要把属性设成空串,你就可以清除它)。只有在你调用initialize 之前,这个操作才有

5,获取进程的进程id   id = IceUtil::generateUUID();

二,
1,slice 中的参数in是client传给ICE对象的,out是ice对象代表的服务参数传给client,client 要想和ICE的服务联系起来就需要一个ice的代理,
只有代理才可以获取ICE对应服务的相关地址,

ICE 中编译slice的方法:slice2cpp name.ice , slice中生成的都是抽象类,具体的服务我们还是需要继承抽象类来具体实例化这些服务的方法的。
ice::exception   ICE根异常分为userexpection和localexpection
ICE中的数据类型在c++中首字母都是大写的,例如Ice::Byte
IceProxy::Ice::Object  是继承一个类,而ObjectPrx则是继承一个代理类。 
Ice::share 
IceUtil::handle 创建一个智能指针,总体来讲是Ice的功能函数较多,比如方法,或者指针处理,字符串处理等等。
Ice::中的对象可以直接与0进行比较的,对于不同的代理而言的话要知道2个代理是不是代表的同一个对象我们要使用Ice所提供的函数proxyIdentityEqual()身份确认函数。
所有的线程API 都是IceUtil 名字空间的一部分。IceUtil::Mutex 类互斥体,IceUtil::Time时间类,class ThreadControl 线程类。

IceBox 服务配置它负责加载和管理的应用特有的服务,并且可以对它进行远地管理
IceStorm 发布/ 订阅服务,充当的是收集器( 发布者) 与监视器( 订阅者)之间的“中间人”,它提供了若干好处:
IceStorm 允许每个订阅者指定它自己的服务质量 (QoS) 参数,IceStorm::QoS qos;是一个词典即map,对其消息的递送施加影响。服务质量参数由一个含有名- 值对的词典表示。
Topic是IceStorm的一个成员。Topic 接口表示一个主题,它提供了若干管理操作,可用于配置链接、管理订阅者。
module IceStorm {
struct LinkInfo {
Topic* theTopic;
string name;
int cost;
};
sequence<LinkInfo> LinkInfoSeq;
dictionary<string, string> QoS;
exception LinkExists {
string name;
};
exception NoSuchLink {
string name;
};
interface Topic {
nonmutating string

2,AMDCallbackCookiePtr& cookie
dynamicCast()是封装dynamic_cast<>方法,作用是:主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
AMDResTransferCallbackCookiePtr myCookie = AMDResTransferCallbackCookiePtr::dynamicCast(cookie);

PUSH::AppServerOutcommPrx outcommPrx = PUSH::AppServerOutcommPrx::uncheckedCast(current.adapter->getCommunicator()->stringToProxy(identity));
    if(!outcommPrx)

所有的代理都派生自共同的IceProxy::Ice::Object类。这个代理基类含有一个方法,可用于创建单向代理,叫作ice_oneway:
注意,我们使用了uncheckedCast 来把代理从ObjectPrx 向下转换成PersonPrx:对于单向代理,我们不能使用checkedCast,因为checkedCast 要求服务器作出答复,而单向代理

当然不允许那样的答复。如果你想要使用安全的向下转换,你可以首先把双向代理向下转换成实际的对象类型,然后再获取单向代理:PersonPrx onewayPerson

=PersonPrx::uncheckedCast(oneway);
然后调用通信器的setStats():单向调用传输数据避免阻塞的话,推荐将in参数的方法和out参数的方法分开来。

3,Ice::Application封装了所有正确的初始化和结束活动,它是启动一个服务的开始方法的继承类
#include <Ice/Ice.h>
class MyApplication : virtual public Ice::Application {
public:
virtual int run(int, char * []) {
// Server code here... 修改的部分
return 0;
}
};
int
main(int argc, char * argv[])
{
MyApplication app;
return app.main(argc, argv);
}

4,通信器提供了一些操作: proxyToString , stringToProxy,这两个操作允许你把代理转换成串化表示,或进行反向转换。
 createObjectAdapter, createObjectAdapterWithEndpoints 这两个操作创建新的对象适配器。每个对象适配器都与一个或更多传输端点关联在一起。
一个对象适配器通常拥有一个传输端点。但是,一个对象适配器也可以提供多个传输端点。

5,传给服务器端的每个骨架操作的最后一个参数(类型是Ice::Current)。Current 对象的定义是:
module Ice {
local dictionary<string, string> Context;
enum OperationMode { Normal, \Nonmutating, \Idempotent };
local struct Current {
ObjectAdapter adapter;
Identity id;
FacetPath facet;
string operation;
OperationMode mode;
Context ctx;
};
};

6,IcePack定位器服务服务器激活和监控服务,用于管理服务器进程 ,Ice::Stats 接口,通信器会把通信流量(发送和接收字节数)告知该对象.

7,插件是用于给通信器增加特性的对象。例如, IceSSL 被实现成插件。每个通信器都有一个插件管理器,这个管理器实现Ice::PluginManager 接口,通过它,
你可以访问通信器的插件集。

三,

C++ 代码生成器为每个AMI 操作生成以下代码:
1. 一个抽象的回调类, Ice run time 用它来通知应用,操作已完成。类名是按这样的模式取的:AMI_class_op。例如,对于在接口I 中定义的名叫foo 的操作 ,
  对应的类的名字是AMI_I_foo。这个类所在的名字空间与操作所属的接口或类相同。这个类提供了两个方法:void ice_response(<params>);
  表明操作已成功完成。各个参数代表的是操作的返回值及out 参数。如果操作的有一个非void 返回类型, ice_response 方法的第一个参数就是操作的返回值。
  操作的所有out 参数都按照声明时的次序,跟在返回值的后面。void ice_exception(const Ice::Exception &);表明抛出了本地或用户异常。

2. 一个额外的代理方法,其名字是操作在映射后的名字,加上_async。这个方法的返回类型是void,第一个参数是一个智能指针,指向上面描述的回调类的一个实例。
其他的参数由操作的各个in 参数组成,次序是声明时的次序。


3,检测ICE配置文件。
 2. 为这个IcePack 节点创建数据库目录结构:
 $ mkdir db
 $ mkdir db/registry
 $ mkdir db/node
 3. 启动这个IcePack 节点。注意,该节点将有一个并置的IcePack 注册表服务,因为在配置文件中定义了IcePack.Node.CollocateRegistry 属性。
 $ icepacknode --Ice.Config=config
4. 在另一个窗口中,启动管理工具,部署该应用。我们假定,应用描述符在文件application.xml 中。在启动icepackadmin 时,我们把同一个配置文件用作icepacknode。
 这样做只是为了方便;管理工具只需要Ice.Default.Locator 属性。
 $ icepackadmin --Ice.Config=config
 >>> application add "application.xml"
 现在,这个应用应该已经部署好了。注意, application.xml 必须放在引号中,因为在icepackadmin 命令语言中, application 是一个关键字。
 你可以使用下面的命令来验证配置:
 >>> server list
 SimpleServer
 >>> adapter list
 IcePack.Node-node
 IcePack.Registry.Internal
 SimpleAdapter-SimpleServer
 >>> object find ::Simple
 SimpleServer -t @ SimpleAdapter-SimpleServer

5,配置路由器
下面的路由器配置属性建立了必需的端点:
Glacier.Router.Endpoints=tcp -h 5.6.7.8 -p 8000
Glacier.Router.Client.Endpoints=tcp -h 5.6.7.8
Glacier.Router.Endpoints 所定义的端点叫做路由器控制端点,
因为Ice run time 会在客户中使用它,直接与路由器交互。Glacier.Router.Client.Endpoints 所定义的端点是有路由的代理发送的请求的目的地。
这些端点都必须能被客户访问,因此会在公共网络接口上定义1。路由器控制端点使用了一个固定的端口,因为客户可能静态配置了针对这个端点的代理。
而客户端点不需要使用固定端口。

6,启动路由器
假定24.3.1 节中给出的配置属性存储在名为config 的文件中,你可以用下面的命令启动路由器:
$ glacierrouter --Ice.Config=config

7,配置客户
下面的属性配置客户中的所有代理,以使用Glacier 路由器:
Ice.Default.Router=Glacier/router:tcp -h 5.6.7.8 -p 8000
参数  name对象适配器的名字。endpoints对象适配器的端点。

抱歉!评论已关闭.