完整mes代码(含客户端和server端_Ice简介+Qt代码示例
一、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中設置連接參數等建立?;畹腎CE連接,達到與服務端的雙向通訊,具體緣由
見代碼注釋。
#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_Hclient 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代码示例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iphonex如何关机_iphonex常
- 下一篇: 电脑有回声_专递课堂互动教室现场有回声怎