您的位置:首页 > 编程语言 > C语言/C++

ICE笔记(05):服务器端Slice到C++映射

2009-11-28 20:19 302 查看


colorado



本文将介绍服务器端的Slice到C++ 映射。客户端Slice到C++映射的内容也适用于服务器端。

1、服务器端的主要流程

从ICE的Hello World应用程序中可以看到,Ice运行时的主入口点为Ice::Communicator。程序必须首先调用Ice::initialize,对Ice运行时进行初始化。Ice::initialize 返回一个指向Ice::Communicator实例的智能指针。根据该指针调用Ice提供的各种服务,实现各项功能。

当关闭Ice程序时,必须调用Communicator::destroy。destroy会确保还在执行的操作完成调用,收回操作系统资源,如果未调用destroy 就终止程序;这样做会导致不确定的行为。

整个流程结构是公式化的代码,Ice提供了Ice::Application 类,封装了Ice运行时的初始、销毁操作。此后,我们将主要使用Ice:Application类,以减少编码工作。

2、Ice::Application类

Applicaiton类的使用:
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);

}

Application类的定义:
namespace Ice {

    enum SignalPolicy { HandleSignals, NoSignalHandling };

    class Application /* ... */ {

    public:

        Application(SignalPolicy = HandleSignals);

        virtual ~Application();

        int main(int argc, char*[] argv);

        int main(int, char*[], const char* config);

        int main(int argc, char*[] argv,const Ice::InitializationData& id);

        int main(const Ice::StringSeq&);

        int main(const Ice::StringSeq&, const char* config);

        int main(const Ice::StringSeq&,const Ice::InitializationData& id);

        virtual int run(int, char*[]) = 0;

        static const char* appName();

        static CommunicatorPtr communicator();

        // ...

    };

}

Application::main 函数的功能:

⑴. 安装了Ice::Exception异常处理器。Ice异常失败,打印到stderr。

⑵. 安装了const std::string & 和const char * 异常处理器。致命错误情况打印到stderr。

⑶. 初始化(通过调用Ice::initialize)和结束(通过调用Communicator::destroy)通信器。用communicator() 访问通信器。

⑷. 处理并删除Ice相关参数,传给run 方法的参数向量只与特定应用程序相关。

⑸. appName返回argv[0],应用程序名。

⑹. 创建了IceUtil::CtrlCHandler,处理中止信号。

⑺. 安装了每进程日志器。以Ice.ProgramName为前缀,日志输出stderr。使用InitializationData结构,可以指定日志器。

Application 类捕获信号的操作:
namespace Ice {

    class Application : /* ... */ {

    public:

        // ...

        static void destroyOnInterrupt();

        static void shutdownOnInterrupt();

        static void ignoreInterrupt();

        static void holdInterrupt();

        static void releaseInterrupt();

        static bool interrupted();

        virtual void interruptCallback(int);

    };

}

IceUtil::CtrlCHandler 类中封装了平台无关的信号处理能力。

Unix:SIGINT、SIGHUP,SIGTERM;

Windows:CTRL_C_EVENT、CTRL_BREAK_EVENT、CTRL_CLOSE_EVENT、CTRL_LOGOFF_EVENT,CTRL_SHUTDOWN_EVENT。

destroyOnInterrupt:

创建IceUtil::CtrlCHandler,当信号产生时销毁通讯器。这是缺省行为。

shutdownOnInterrupt:

创建IceUtil::CtrlCHandler,当信号产生时关闭通讯器。

ignoreInterrupt:

忽略信号

callbackOnInterrupt:

信号发生时,Ice::Application调用interruptCallback,以便子类处理信号 。如果信号处理器要终止程序,必须调用_exit,而不是exit。

holdInterrupt:

阻塞信号

releaseInterrupt:

发送被阻塞的信号

interrupted:

信号关闭了通讯器,返回true;否则返回false,表示正常有关闭。

interruptCallback

子类重写本函数,响应信号。

MyApplication  app; //或app(HandleSignals); 默认处理信号

MyApplication  app(NoSignalHandling); //不处理信号

如果服务器被信号中断,Ice运行时会等待目前正在执行的所有操作完成。才会完成信号处理。

Application负责用属性值初始化Ice运行时,它是单例类,创建单个通信器。如果要创建多个通讯器,必须使用类似Ice的Hello World程序那样的常规代码结构。

3、Ice::Service 类

类似Application类,可以作为系统服务运行。要实现这项功能,至少要重写start类。

Service类的使用:
#include <Ice/Service.h>

class MyService : public Ice::Service {

protected:

    virtual bool start(int, char * []);

private:

    Ice::ObjectAdapterPtr _adapter;

};

bool MyService::start(int argc, char * argv[])

{

    _adapter = communicator()->createObjectAdapter("MyAdapter");

    _adapter->addWithUUID(new MyServantI);

    _adapter->activate();

    return true;

}

int main(int argc, char * argv[])

{

    MyService svc;

    return svc.main(argc, argv);

}

Service类的定义:
namespace Ice {

    class Service {

    public:

        Service();

        virtual bool shutdown();

        virtual void interrupt();

        int main(int&, char*[],const Ice::InitializationData&=Ice::InitializationData());

        int main(Ice::StringSeq&,const Ice::InitializationData&=Ice::InitializationData());

        Ice::CommunicatorPtr communicator() const;

        static Service * instance();

        bool service() const;

        std::string name() const;

        bool checkSystem() const;

        int run(int&, char*[], const Ice::InitializationData&);

        void configureService(const std::string&);

        void configureDaemon(bool, bool, const std::string&);

        virtual void handleInterrupt(int);

    protected:

        virtual bool start(int, char * []) = 0;

        virtual void waitForShutdown();

        virtual bool stop();

        virtual Ice::CommunicatorPtr initializeCommunicator(int &,char * [],

 const Ice::InitializationData&);

        virtual void syserror(const std::string &);

        virtual void error(const std::string &);

        virtual void warning(const std::string &);

        virtual void trace(const std::string &);

        void enableInterrupt();

        void disableInterrupt();

        // ...

    };

}

Service.main

⑴、分析处理参数向量

⑵、配置configureService/configureDaemon

⑶、运行run

Service.run

⑴、安装CtrlCHandler处理信号

⑵、初始化通讯器

⑶、调用start

⑷、调用waitForShutdown

⑸、调用stop

⑹、销毁通讯器

⑺、得体地终止服务

Service成员函数:

handleInterrupt

信号发生时由CtrlCHandler调用,缺省忽略信号。

initializeCommunicator

初始化通讯器,缺省Ice::initialize

interrupt

信号处理器调用它表示收到信号, 缺省实现调用shutdown。

shutdown

关闭服务器

start

启动:参数处理,创建对象适配器,注册服务者……

stop

终止之前的清理

syserror,error,warning,trace,print 将消息记录到通讯器日志器中。

waitForShutdown

等待服务关闭,缺省实现是调用通讯器的waitForShutdown。

checkSystem:

支持服务,返回true。

disableInterrupt

禁用信号

enableInterrupt

启用信号,handleInterrupt处理

configureDaemon

configureService

*instance

服务实例

name

服务名称

run

必须设置configureDeamon/configService作为服务运行。

service

是服务,返回true。

日志

Windows上,不设置日志器,会记录到系统事件日志中。

Unix上,使用Ice.UseSyslog指日志器,Ice.StdErr将错误重定向到文件。

命令行参数:

Unix平台上 --daemon参数指明程序应该作为守护程序运行。

Windows平台上 --service NAME参数指明程序作为NAME服务运行。

 

有关Ice::Application和Ice::Service 相关信息还可以参考ydogg
博客的相关文章。

4、接口映射

在客户端,接口映射到代理类。在服务器端,接口映射到骨架类。骨架类是抽象类,成员函数为纯虚函数,继承自Ice::Object。

服务者类

服务者类继承并实现对应的骨架类。在定义服务者类时建议总是使用虚继承。严格地说,只有其实现的接口使用了多继承的服务者才必须使用虚继承;但virtual关键字并无害处,同时,如果在开发中途要给接口层次增加多继承,无需回去给服务者类增加virtual 关键字。

5、参数传递

Slice规范的操作:

string op(string sin, out string sout);

C++映射代码:

virtual std::string op(const std::string &, std::string &,const Ice::Current & = Ice::Current()) = 0;

• in 参数通过值或const 引用传递。

• out 参数通过引用传递。

• 返回值通过值传递。

• 在Slice规范中["cpp:const"]指令可以指定const成员函数。

6、异常

异常:只抛出Slice异常规范中定义的异常。

抛C++异常,客户会收到UnknownException;

抛未在异常规范中定义的用户异常,客户会收到UnknownUserException;

抛Ice运行时异常,客户会收到UnknownLocalException。

7、激活服务者

NodePtr servant = new NodeI(name);

Ice::Identity id;

id.name = name;

MyAdapter->add(servant, id); 

⑴. 实例化服务者类

在堆上创建NodeI实现类,赋给智能指针servant。如果要调用NodeI类的成员函数,应该定义NodeIPtr智能指针:

typedef IceUtil::Handle<NodeI> NodeIPtr;

NodeIPtr servant = new NodeI(name);

⑵. 服务者对应的Ice对象创建标识

struct Identity {

    string name;

    string category;

};

通常category为空。只为name赋值。

⑶. 激活服务者

MyAdapter->add(servant, id);

将代表服务者的智能指针servant,以及标识id添加到适配器的服务者映射表(ASM)中,从而激活了服务者。可以接收客户端的服务了。客户端代理包含服务器寻址信息,请求的Ice对象标识id,客户调用操作时,对象标识一同发给服务器,服务器根据对象id查找ASM表,找到该标识的服务者,就把请求分派给它的成员函数。

MyAdapter->addWithUUID(servant);

未指定标识,使用UUID作为对象标识,也可以使用IceUtil::generateUUID()创建全局唯一标识,再赋给add操作。

⑷. 创建代理

NodePrx proxy = NodePrx::uncheckedCast(MyAdapter->add(servant, id));

现在,可以将proxy传给客户端使用了。

Ice提供了直接创建代理的操作:

Ice::Identity id;

id.name = IceUtil::generateUUID();

ObjectPrx o = MyAdapter->createProxy(id);

无论对象标识id对应的服务者是否被激活,该操作都会创建的代理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息