一、ICE是什么?

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

2: ICE的安装和示例

2.1 ICE安装

   ICE官网:,点击download后选择合适的平台/开发环境便可,的安装以下图。python

notes: 注意与版本差别较大,头文件不互相兼容,选用时需注意客户端/服务端ICE版本的一致性,避免代码没法编译经过。c++

: hello world代码示例

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

首先建立一个slice文件,并将程序须要远程调用的接口写入其中。对于hello world程序,slice文件可按以下来写: github

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

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

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

#include <Ice/Ice.h>
#include <>usingnamespace std;
usingnamespace Demo;class PrinterI : public Printer
{
public:virtualvoid printString(string s, const Ice::Current&) override;
};void
PrinterI::printString(string s, const Ice::Current&)
{cout << s << endl;
}int
main(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 << () << endl;return1;}return0;
}

客户端须要建立远程对象的代理,并经过代理进行远程调用,代码以下:网络

#include <Ice/Ice.h>
#include <>
#include <stdexcept>usingnamespace std;
usingnamespace Demo;int
main(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 << () << endl;return1;}return0;
}

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

完整可运行的Qt工程(可复用的ICE通讯模板)可参考并发

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 ""usingnamespace 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*/CustomEvent *e = new CustomEvent(QEvent::Type(QEvent::User + CustomEvent::CustomEvent_RequireService));e->m_params   = s;e->m_callback = Ice::uncheckedCast<Demo::ClientCallbackPrx>(current.con->createProxy(Ice::stringToIdentity(ident)));QCoreApplication::postEvent(m_implement, e);}private:QObject *m_implement;
};class IceManager
{
public:IceManager() {/* set up global ice configurations, here we just set thread pool to 2 to avoid deadlock on ice callback,* other settings are configurable as the same.*/Ice::PropertiesPtr props0 = Ice::createProperties();props0->setProperty("", "2");props0->setProperty("Max", "2");props0->setProperty("", "2");props0->setProperty("Max", "2");props0->setProperty("", "1");Ice::InitializationData id;id.properties = props0;m_ich = Ice::CommunicatorHolder(id);}bool setImplement(QObject *implement) {try {/* create server object and add it to ice adapter to receive client requirements.* The adapter identification is used for ice pack service, we donot use it now.* The endpoints is the location url where client can access to require service.* The servant identification is used to identify servant as we can add multiple servants to one adapter.*/shared_ptr<ServerI> servant = make_shared<ServerI>();servant->setImplement(implement);auto adapter = m_ich->createObjectAdapterWithEndpoints("ServerAdapter", "default -h localhost -p 10000");adapter->add(servant, Ice::stringToIdentity("Server"));adapter->activate();} catch (const exception &e){cout << "Failed to create ice server object, error-->%s" << () << endl;returnfalse;}returntrue;}private:Ice::CommunicatorHolder m_ich;
};class MainWorker : public QObject
{
public:MainWorker(QObject *parent = nullptr) : QObject(parent) {}protected:/* Receive client requirements and deliver to associated servcie function */void customEvent(QEvent *e) {CustomEvent *event = (CustomEvent *)e;int type = event->type() - QEvent::User;if (CustomEvent::CustomEvent_RequireService == type) {renderService(event->m_params, event->m_callback);} else {cout << "Unrecognized event type-->" << type << "!" << endl;}}private:/* a simple implement */void renderService(conststring& s, const Demo::ClientCallbackPrxPtr& callback) {cout << s << endl;callback->callback("Requirement done!");}
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);MainWorker worker(&a);IceManager ice_manager;(&worker);return a.exec();
}

client端 头文件代码:客户端基本上与服务端相似, 可是多了一个主动发起请求的IceRequirer类,并在IceRequirer中设置连接参数等建立保活的ICE连接,达到与服务端的双向通讯,具体缘由

见代码注释。

#ifndef HELPER_H
#define HELPER_H#include <QTimer>
#include <QEvent>
#include <QObject>
#include <QThread>
#include <QCoreApplication>#include <stdexcept>#include <Ice/Ice.h>
#include ""usingnamespace std;/* custom event used for event loop */class CustomEvent : public QEvent
{
public:explicit CustomEvent(Type type) :QEvent(type) {}enum PMAlgoEventType {CustomEvent_RequireCallback = 0x00000001,};string m_params;
};class ClientI : public Demo::ClientCallback
{
public:ClientI(){}/* 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_server_implement = implement;}void callback(string s, const ::Ice::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.* s : params used for servcie*/CustomEvent *e = new CustomEvent(QEvent::Type(QEvent::User + CustomEvent::CustomEvent_RequireCallback));e->m_params    = s;QCoreApplication::postEvent(m_server_implement, e);}private:QObject *m_server_implement;
};class ServerRequirer : public QObject
{Q_OBJECT
public:explicit ServerRequirer(const Ice::CommunicatorHolder &ich, const Ice::ObjectAdapterPtr &adapter, conststring& ident) {m_ic        = ();m_adapter   = adapter;m_ident     = ident;}public slots:void slot_requireServcie(conststring& s) {if (nullptr == m_server_prx.get()) {/* connection is not established, try to establish connection first */try {auto base = m_ic->stringToProxy("Server:default -h localhost -p 10000");m_server_prx = Ice::checkedCast<Demo::ServerServicePrx>(base);if(nullptr != m_server_prx.get()){/* set up eseential configurations on Ice connection to keep this connection alive */m_server_prx->ice_getConnection()->setACM(Ice::nullopt, Ice::ACMClose::CloseOff, Ice::ACMHeartbeat::HeartbeatAlways);m_server_prx->ice_getConnection()->setAdapter(m_adapter);}}catch(const exception& e){cerr << () << endl;}}if (nullptr != m_server_prx.get()) {try {/* require remote object call via object proxy */m_server_prx->requireService(m_ident, s);}catch(const exception& e){/* connection lost, reset it and re-establish it on next call */cerr << () << endl;();}}}private:string m_ident;Ice::CommunicatorPtr      m_ic;Ice::ObjectAdapterPtr     m_adapter;Demo::ServerServicePrxPtr m_server_prx;
};class IceManager : public QThread
{Q_OBJECT
public:/* Craete ice global communicator and manager ice requirement.* Server requirements are posted in seperate thread as they may be time-consuming* Local object that implements callback is identified through bidirectional connection instead of* creating a new connection fron server to client, as client may be defensed behind firewall or local network.*/IceManager() {/* register qt meta type */qRegisterMetaType<string>("string");/* set up global ice configurations, here we just set thread pool to 2 to avoid deadlock on ice callback,* other settings are configurable as the same.*/Ice::PropertiesPtr props0 = Ice::createProperties();props0->setProperty("", "2");props0->setProperty("Max", "2");props0->setProperty("", "2");props0->setProperty("Max", "2");props0->setProperty("", "1");/* create global ice communicator */Ice::InitializationData id;id.properties = props0;m_ich = Ice::CommunicatorHolder(id);}bool start(QObject *implement) {try {/* create client object and add it to ice adapter to receive server callbacks.* The adapter is created without identification as we donot access it by endpoints.* Instead, we pass it through the connection established with server to build a bidirectional connection.*/m_ident = "Client";shared_ptr<ClientI> servant = make_shared<ClientI>();servant->setImplement(implement);m_adapter = m_ich->createObjectAdapter("");m_adapter->add(servant, Ice::stringToIdentity(m_ident));m_adapter->activate();} catch (const exception &e) {cout << "Failed to create ice object, error-->%s" << () << endl;returnfalse;}/* create ice service requirer in seperate thread, as network request may be time-consuming */m_requirer = new ServerRequirer(m_ich, m_adapter, m_ident);m_requirer->moveToThread(this);connect(this, SIGNAL(signal_requireService(string)), m_requirer, SLOT(slot_requireServcie(string)));QThread::start();returntrue;}public slots:void slot_requireService() {string s("Hello world!");emit signal_requireService(s);}signals:void signal_requireService(string s);private:Ice::CommunicatorHolder m_ich;Ice::ObjectAdapterPtr   m_adapter;string          m_ident;        /* local object identification */ServerRequirer *m_requirer;
};class MainWorker : public QObject
{
public:MainWorker(QObject *parent = nullptr) : QObject(parent) {}protected:/* Receive callbacks from server and deliver to associated callback function */void customEvent(QEvent *e) {CustomEvent *event = (CustomEvent *)e;int type = event->type() - QEvent::User;if (CustomEvent::CustomEvent_RequireCallback == type) {renderCallback(event->m_params);} else {cout << "Unrecognized event type-->" << type << "!" << endl;}}private:/* a simple implement */void renderCallback(conststring& s) {cout << s << endl;}
};#endif// HELPER_H

client main文件代码

#include ""int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);/* local worker */MainWorker worker(&a);/* ice service manager */IceManager ice_manager;(&worker);/* require serve service every 3 seconds */QTimer timer;QObject::connect(&timer, SIGNAL(timeout()), &ice_manager, SLOT(slot_requireService()));(3 * 1000);return a.exec();
}

完整mes代码(含客户端和server端_Ice简介+Qt代码示例相关推荐

  1. 完整mes代码(含客户端和server端_200行代码实现基于paxos的kv存储

    本文链接: https://blog.openacid.com/algo/paxoskv/ 前言 写完 paxos的直观解释 之后, 网友都说疗效甚好, 但是也会对这篇教程中一些环节提出疑问(有疑问说 ...

  2. NodeJS SSR服务端渲染:公共代码区分客户端和服务端

    SSR服务端渲染(英语:server side render)指一般情况下,一个web页面的数据渲染完全由客户端或者浏览器端来完成.先从服务器请求,然后到页面:再通过AJAX请求到页面数据并把相应的数 ...

  3. 用Python写了个websocket即时聊天网页(含客户端、服务端代码)

    其他的不说,原理自己搜下,直接上代码 客户端代码: <html> <head> <title>WebSocket</title><script s ...

  4. html移动端隐藏代码,html Css PC 移动端 公用部分样式代码整理

    css常用公用部分样式代码整理: body, html, div, blockquote, img, label, p, h1, h2, h3, h4, h5, h6, pre, ul, ol, li ...

  5. linux epoll机制对TCP 客户端和服务端的监听C代码通用框架实现

    1 TCP简介 tcp是一种基于流的应用层协议,其"可靠的数据传输"实现的原理就是,"拥塞控制"的滑动窗口机制,该机制包含的算法主要有"慢启动&quo ...

  6. SSO单点登录教程案例 客户端和服务端

    这里写自定义目录标题 前言 条件 环境要求 准备工作 下载基础项目 项目结构说明 执行流程图 代码实现 单点登录步骤梳理: 代码下载 前言 文章摘抄:https://www.jianshu.com/p ...

  7. 手机移动端可滚动的导航代码

    主要代码如下: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" ...

  8. react-template 包含客户端,服务端渲染完整示例

    原文链接 React version 16.2 版本脚手架 包含客户端,服务端渲染完整示例,使用了最新的react,并实现version 16.2 最新的服务端渲染; 解决了一些之前的服务端渲染bug ...

  9. gPRC简介以及Java中使用gPRC实现客户端与服务端通信(附代码下载)

    场景 ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/det ...

最新文章

  1. OpenAI 发布通用人工智能研究纲领:以全人类的名义承诺
  2. 赛灵思CEO Victor Peng:中国AI市场创新速度令人振奋,但初创企业应避免扎堆做AI芯片...
  3. 液晶字体数字一到九_睡前必听3分钟系列十一:光传输设备和同步数字体系的特点...
  4. 【WPF-Devexpress】ChartControl-CrosshairLabel显示内容居右
  5. 易语言开发c s,Grid++Report报表工具C/S实战项目演练
  6. 应用容器公共免费部署平台
  7. 计算机文件图标怎么一致大小,电脑图标大小设置的几种方法
  8. 欧标语言等级划分 C1,小语种欧标等级的要求
  9. YB4556系列 28V 高输入耐压4056 可支持4.2V 4.3V 电池 并且具有多种封装方式 可应用于电子烟 充电器 等各类产品
  10. 网吧服务器哪个好稳定,网吧服务器不应盲目追高新:够用稳定就好
  11. 用Python实现数据筛选与匹配
  12. 2021辽宁省大学生程序设计竞赛(C、D、E、F、G、L)
  13. 并发编程笔记——第六章 Java并发包中锁原理剖析
  14. win10怎么把网络里面计算机删除,win10怎么删除多余的网络连接 win10网络连接不可用怎么回事...
  15. android mma
  16. Python聊天室设置与实现
  17. 基于STM32智能人体红外和声音感应声光控开关设计
  18. 深度学习之学习笔记(九)—— 误差反向传播法
  19. OCR技术系列之一 字符识别技术总览
  20. nyoj995硬币找零(dp)

热门文章

  1. 看看人家 SpringBoot + vue后台管理系统,多么优雅...
  2. 今年的校招,Java好拿offer吗?
  3. Nginx在Windows平台的配置与使用
  4. SpringMVC中@RequestMapping 6个基本用法小结
  5. Eclipse实现hibernate反向工程:从数据库逆向生成实体类和hbm文件
  6. Eclipse自动注册Servlet:web.xml注册和@Servlet注解 实现注册
  7. 【小练习06】HTML+CSS--电影公告
  8. ping得通dns却无法上网_一款好用的DNS服务器SmartDNS
  9. 杭电2037java实现
  10. 通俗易懂:贪心算法(三):习题练习 (力扣605种花问题、122买卖股票的最佳时机)