Ice简介 Qt代码示例

1、ICE是什么?ICE是ZEROC的开源通信协议产品,它的全称是:TheInternetCommunicationsEngine,翻译为中文是互联网通信引擎,是一个面向对象的中间件,它封装并实现了底层的通讯逻辑,使我们能够方便的构建分布式应用程序。相对于只面向WINDOWS系统微软的.NET(以及原来的DCOM)、复杂的CORBA及性能较差的WEBSERVICE等分布式方案,ICE很好的解决了这...

Ice简介 Qt代码示例

1、ICE是什么?

ICE是ZEROC的开源通信协议产品,它的全称是:The Internet Communications Engine,翻译为中文是互联网通信引擎,是一个面向对象的中间件,它封装并实现了底层的通讯逻辑,使我们能够方便的构建分布式应用程序。相对于只面向WINDOWS系统微软的.NET(以及原来的DCOM)、复杂的CORBA及性能较差的WEB SERVICE等分布式方案,ICE很好的解决了这些中间件的不足:它支持不同的系统,如WINDOWS、LINUX等,支持在多种开发语言上使用,如C 、C、JAVA、RUBY、PYTHON、VB等。服务端可以是上面提到的任何一种语言实现的,客户端也可以根据自己的实际情况选择不同的语言实现,如服务端采用C语言实现,而客户端采用JAVA语言实现等。

2: ICE的安装和示例

2.1 ICE安装

  ICE官网:https://zeroc.com,点击download后选择合适的平台/开发环境即可,Ubuntu18.04的安装如下图。

notes: 注意ICE3.7.2与3.6.x版本差异较大,头文件不互相兼容,选用时需注意客户端/服务端ICE版本的一致性,避免代码无法编译通过。

2.2: hello world代码示例

官网的helloworld程序,详见官网目录https://doc.zeroc.com/ice/3.7/hello-world-application

首先创建一个slice文件Printer.ice,并将程序需要远程调用的接口写入其中。对于hello world程序,slice文件可按如下来写:

module Demo{ interface Printer {  void printString(string s); }}

下面我们以C (c 11)为例,分别实现服务端和客户端。首先,我们使用slice2cpp将ice文件转换成C 可使用的.h和.cpp文件。其中.h文件中包含了我们需要远程调用的接口定义以及ICE封装,最主要的有Printer和PrinterPrx类,分别是服务端需要实现的具体对象和客户端使用的代理,其中PrinterPrx代理类中还提供了printStringAsync异步调用方法。

slice2cpp Printer.ice  

服务端需要实现Printer类的接口,并创建本地创建,之后添加到ice适配器上,以便客户端远程调用。具体实现代码如下:

#include <Ice/Ice.h>#include <Printer.h> using namespace std;using namespace Demo; class PrinterI : public Printer{public: virtual void printString(string s, const Ice::Current&) override;}; void PrinterI::printString(string s, const Ice::Current&){ cout << s << endl;} intmain(int argc, char* argv[]){ try {  Ice::CommunicatorHolder ich(argc, argv);  auto adapter = ich->createObjectAdapterWithEndpoints("SimplePrinterAdapter", "default -h localhost -p 10000");  auto servant = make_shared<PrinterI>();  adapter->add(servant, Ice::stringToIdentity("SimplePrinter"));  adapter->activate();  ich->waitForShutdown(); } catch(const std::exception& e) {  cerr << e.what() << endl;  return 1; } return 0;}

客户端需要创建远程对象的代理,并通过代理进行远程调用,代码如下:

#include <Ice/Ice.h>#include <Printer.h>#include <stdexcept> using namespace std;using namespace Demo; intmain(int argc, char* argv[]){ try {  Ice::CommunicatorHolder ich(argc, argv);  auto base = ich->stringToProxy("SimplePrinter:default -p 10000");  auto printer = Ice::checkedCast<PrinterPrx>(base);  if(!printer)  {throw std::runtime_error("Invalid proxy");  }printer->printString("Hello World!"); } catch(const std::exception& e) {  cerr << e.what() << endl;  return 1; } return 0;}

上面的demo演示了ice远程调用的基本工作方式,ICE接口的详细解释既可通过ICE官网查看,也可在安装ICE后查看相应的头文件注释。然而实际工程中我们需要对ice进行配置,处理网络异常,在服务端进行回调,穿透防火墙,进行线程调度等工作。虽然在ICE的chat demo中有介绍这些工作,然而其demo中引入了Glacier2 rooter中session的使用,而github中代码复杂度更高。相反,以上这些工作不通过Glacier2 rooter也能完美的解决,详见如下代码及注释。

完整可运行的Qt工程(可复用的ICE通信模板)可参考https://github.com/leaf-yyl/ice_template

ICE 文件: 定义了一个服务端需要提供的服务 以及一个客户端需要的回调

module Demo{ interface ServerService {  void requireService(string ident, string s); } interface ClientCallback {  void callback(string s); }}

server端代码 : 服务器端worker对象提供具体的服务, ice_manager对象负责ic模块的管理,并接收客户端请求,这些请求会在不同的ICE线程中接收到,然后通过postevent函数最终全部转发到

worker的工作线程并依序处理,如果提供的服务是线程安全的且需要高并发,那么可以去除这一步以获得高性能。相反,如果worker提供的服务不是线程安全的,或者worker中存在线程相关的资源

(例如python解释器等),则必须通过事件循环或者消息队列将ICE线程收到的客户端请求汇总到worker线程统一处理。

#include <QEvent>#include <QObject>#include <QCoreApplication>#include <stdexcept>#include <Ice/Ice.h>#include "Printer.h"using namespace std;class CustomEvent : public QEvent{public: explicit CustomEvent(Type type) :QEvent(type) { } enum PMAlgoEventType {  CustomEvent_RequireService = 0x00000001, }; string m_params; Demo::ClientCallbackPrxPtr m_callback;};class ServerI : public Demo::ServerService{public: ServerI(){} /* Use event loop implement in QObject by Qt to post client requirements to user thread.  * May be replaced by event loop in pure C  , handler in java and so on.  */ void setImplement(QObject *implement) {  m_implement = implement; } void requireService(string ident, string s, const ::Ice::Current& current) override {  /* we donot generate the client requirement here, but post it to main thread as this function is called in ice server threads.* When the interface is not thread safe or time-consuming, or has thread associated context like python interpreter, we must post* it to a constant thread managered by ourself to avoid running exceptions.* ident : client object identification, used to build bidirectional connection to cross firewall and local network* s : params used for servcie*/  CustomEv
源文地址:https://www.guoxiongfei.cn/cntech/14874.html
0