ZeroC Ice介紹與簡單demo構建
本文主要介紹ZeroC Ice的相關知識,以及如何構建一個Ice的demo程式。
1. ZeroC Ice介紹
Ice(Internet Communications Engine)是一個面向物件的RPC框架,它可以幫助你輕鬆地構建分散式應用。通過使用Ice,使用者可以將更多的注意力放在自己應用程式的邏輯上,至於底層網路程式介面的互動則由Ice負責。通過使用Ice,使用者不需要再為一些細節擔憂,例如開放式網路連線、網路傳輸的序列化和反序列化,以及連線的失敗重傳問題。
ZeroC Ice的客戶端和服務端的架構圖如下:
2. demo構建
說明:本文介紹的demo程式是在Centos 7上、使用C++語言開發的,對應的Ice版本為3.6.4。
2.1 安裝Ice
1. 新增Ice的yum倉庫:
cd /etc/yum.repos.d
wget https://zeroc.com/download/Ice/3.6/el7/zeroc-ice3.6.repo
2. 安裝Ice:
yum install ice-all-runtime ice-all-devel
2.2 編寫Slice定義檔案
開發Ice程式的第一步就是編寫Slice定義檔案,該檔案包含了Ice應用程式需要用到的介面。
在本文中,我們編寫名為Hello.ice的Slice定義檔案,Hello.ice內容如下:
module Demo { interface Hello { string SayHello(string username); }; };
上面的Slice定義檔案內,包括了Demo模組,Demo模組中又包含了Hello介面。當前,Hello介面僅提供了一個操作:SayHello。SayHello操作的具體功能需要我們後續去實現。
2.3 編譯Slice定義檔案
編譯前面編寫的Slice定義檔案,生成編譯C++所需要的檔案,命令如下:
slice2cpp Hello.ice
根據Hello.ice,上面的命令會生成兩個檔案:Hello.h和Hello.cpp。其中:
Hello.h:Hello.h標頭檔案包含了Slice定義檔案中定義的Hello介面(當前,現在這個介面是以C++型別定義的),在客戶端與服務端的原始碼中都要包含Hello.h。
Hello.cpp:
說明:從架構角度看,由Hello.ice生成的Hello.h和Hello.cpp,相當於C++的 proxies 和 skeletons。
2.4 編寫介面處理類宣告及實現程式碼
建立介面處理類HelloI,HelloI繼承了生成類Hello(由*.ice檔案生成)。在HelloI中定義了(*.ice檔案中)SayHello操作的具體實現。
類HelloI宣告程式碼(HelloI.h)如下:
#ifndef __HELLOI_H__
#define __HELLOI_H__
#include <Hello.h>
using namespace std;
class HelloI : public Demo::Hello
{
public:
virtual string SayHello(const string&, const Ice::Current&);
};
#endif
類HelloI的實現程式碼(HelloI.cpp)如下:
#include <Ice/Ice.h>
#include <HelloI.h>
using namespace std;
string HelloI::SayHello(const string& s, const Ice::Current&)
{
string wholestr;
cout << "server receive msg: " << s << endl;
wholestr = "hello " + s;
cout << "server return msg: " << wholestr << endl;
return wholestr;
}
注意:本文到現在為止,介紹的幾個檔案(Hello.ice、Hello.h、Hello.cpp、HelloI.h、HelloI.cpp)為本ZeroC Ice系列部落格的demo搭建時使用的基礎框架檔案,後面對於ZeroC各個應用模式的demo搭建,如無特殊說明,均沿用了這五個基礎檔案。現給出ZeroC各應用模式的demo連結如下:
2.5 編寫服務端程式碼
服務端程式碼建立介面處理類HelloI的例項,並將該例項關聯到指定的Ice物件ID(本例中Ice物件ID為“hello”),客戶端通過這個Ice物件ID呼叫服務端(介面處理類中定義的)方法。
服務端程式碼(server.cpp)如下:
#include <Ice/Ice.h>
#include <HelloI.h>
using namespace std;
int main(int argc, char* argv[])
{
int status = 0;
Ice::CommunicatorPtr ic;
try
{
ic = Ice::initialize(argc, argv);
Ice::ObjectAdapterPtr adapter = ic->createObjectAdapterWithEndpoints("HelloAdapter", "default -p 10000");
Ice::ObjectPtr object = new HelloI;
adapter->add(object, ic->stringToIdentity("hello"));
adapter->activate();
cout << "server started, waiting for client connect..." << endl;
ic->waitForShutdown();
}
catch (const Ice::Exception& e)
{
cerr << e << endl;
status = 1;
}
catch (const char* msg)
{
cerr << msg << endl;
status = 1;
}
if (ic)
{
try
{
ic->destroy();
}
catch (const Ice::Exception& e)
{
cerr << e << endl;
status = 1;
}
}
return status;
}
2.6 編寫客戶端程式碼
客戶端程式碼通過服務端提供的Ice物件ID連線服務端,並呼叫(與該Ice物件ID)相關的方法。
客戶端程式碼(client.cpp)如下:
#include <Ice/Ice.h>
#include <Hello.h>
using namespace std;
using namespace Demo;
int main(int argc, char* argv[])
{
int status = 0;
Ice::CommunicatorPtr ic;
try
{
ic = Ice::initialize(argc, argv);
Ice::ObjectPrx base = ic->stringToProxy("hello:default -p 10000");
HelloPrx hello = HelloPrx::checkedCast(base);
if (!hello)
{
throw "Invalid proxy";
}
string result = "";
result = hello->SayHello("liitdar");
cout << "client's result: " << result << endl;
}
catch (const Ice::Exception& ex)
{
cerr << ex << endl;
status = 1;
}
catch (const char* msg)
{
cerr << msg << endl;
status = 1;
}
if (ic)
{
ic->destroy();
}
return status;
}
2.7 編譯生成客戶端和服務端的應用程式
編譯生成服務端應用程式(server),命令如下:
g++ -o server -I. server.cpp Hello.cpp HelloI.cpp -lIce -lIceUtil -lpthread
編譯生成客戶端應用程式(client),命令如下:
g++ -o client -I. client.cpp Hello.cpp -lIce -lIceUtil -lpthread
2.8 執行服務端與客戶端程式
在一個終端執行服務端程式,如下:
./server
新開啟一個終端,執行客戶端程式,如下:
./client
正常情況下,我們能夠在上面的兩個終端中看到服務端與客戶端的資訊互動情況,如下:
【服務端】:
【客戶端】:
如果兩個終端中出現了上述資訊,說明demo程式部署成功了。
上述資訊互動過程為:
a)服務端啟動,等待客戶端連線;
b)客戶端連線服務端,傳送“liitdar”到服務端,呼叫服務端的SayHello方法(“liitdar”作為SayHello方法的引數);
c)服務端執行SayHello方法,並在終端上列印相關資訊;
d)服務端將SayHello方法的返回值返回給客戶端;
e)客戶端收到服務端的返回值,列印該返回值。