三 ICE開發初級研究
睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接
http://www.acejoy.com/bbs/viewthread.php?tid=2878&extra=page%3D1
ICE開發初級研究(一)
最近一段一直在忙于工作,事情比較多,除了偶爾在這里看看帖子,一直沒有寫什么東西。再加上忙于PurenessScopeSerever0.72版本的開發,爭取0.72版再次給大家帶來一些提升。其實想想,技術這種東西,并非一定要高深到誰也看不懂才叫牛。技術這樣的東西,分享是很關鍵的。只有簡單好用的技術,才會獲得大規模的應用。
ICE這個東西,說實話以前我比較懼怕。到處看到的文章都是說,重量級的中間件,雖說是源于Corba,但是復雜度感覺不低于ACE。網上搜索ICE也都是比較基礎的應用。最近工作用到了,想跟著工作的進度,陸續寫一些ICE有關的實際應用。供大家參考和使用,拋磚引玉。這里特別感謝True的大力支持。現在看來,ICE還是不用懼怕的,ACE都能活下來,再看ICE實際變的簡單了,呵呵。里面難免有些偏頗之處,請大家指正。
廢話少說,要用ICE,需要先去官網下載一個ICE的開發庫。
ICE的開發官網是http://www.zeroc.com,目前最新版本是3.4.1。
下載地址為:http://www.zeroc.com/download.html 這里我吃了一個虧(我在windows下使用,linux下倒是少了這些麻煩),因為沒注意版本,我本人用的是VS2005,結果后來編碼完后,運行竟然到處報錯。后來才知道ICE的3.4.1只支持VS2008 SP1以后的開發環境(感覺怎么ICE的開發者就不能像ACE的開發者那樣,支持多版本的編譯器呢?),如果你是VS2005環境的話,建議下載3.3.1,如果是2008,建議下載3.4.0,如果是2008 SP1之后的版本,建議使用3.4.1。
如果是windows推薦下載msi版本,linux的話下載rpm,安裝都比較省事,一路下一步就行了。
安裝后打開環境變量,按照ACE的推薦那樣設置一下你的ICE路徑
然后打開你的VS2005,先建立一個服務器端(win32控制臺程序)。(我的環境變量叫做ICE_ROOT)
然后在打開工程屬性,里面添加C++附加路徑($(ICE_ROOT\include))和你的lib附加路徑($(ICE_ROOT)\lib),然后添加需要用到的iced.lib iceutild.lib
行了,這個工程就可以寫ICE的程序了。
ICE使用前需要定義一個接口文件。一般是*.ice命名的(*是你起的名字,比如我的例子是TestICE.ice)
#ifndef _TESTICE_H
#define _TESTICE_H
module Test
{
interface TestICE
{
int ping();
int GetTime(out string strTime);
};
};
#endif
這里是一個接口文件,我來給大家一行行解釋。(其實大部分寫法都是固定的)
首先,你必須定義你的接口的一個NameSpace的名字。
這里比如module Test
意思就是你聲明了一個叫做Test的命名空間,這個是很重要的,因為未來在你的代碼中,要寫上using namespace Test。
下面是
interface TestICE
這里是你聲明的接口名稱。這個就像把很多網線捆起來的束,在訪問的時候,要先找到束,再找里面對應的接口。這樣做,很方便管理你的接口,比如你可以定義一個DB接口集合,一個Logic接口集合。。。。層次感會跟清晰。
我在我的TestICE里面,定義了兩個函數。
int ping();
int GetTime(out string strTime);
這里,我這兩個函數都沒有具體實現,呵呵,只是為了測試而已。
然后,這個文件寫好了,進入你的ICE的安裝路徑,進入bin目錄,然后cmd進入這個目錄。在命令行敲入slice2cpp TestICE.ice 這里要說明一下,如果你使用的是路徑,比如slice2cpp d:\TestICE.ice 這樣是可以的,但是如果路徑中有中文,會報錯。
如果一切順利,你將會在你的*.ice路徑下得到兩個文件,一個.h一個.cpp。其實感覺,如果你能仔細分析懂這些代碼,弄個模板自己改一個也行,不需要ICE幫你生成,當然,簡單起見,還是ICE的工具比較方便,畢竟可以幫你檢查語法。
有了這兩個文件,直接拷貝到你的Server和Client工程中,這兩個都需要用。
然后寫一個類,繼承這個接口的虛類。
#include "TestICE.h"
#include <string>
using namespace std;
using namespace Test;
class CTest : public TestICE
{
public:
int ping(const Ice::Current&);
int GetTime(string& strTime, const Ice::Current&);
};
class CMainServer : public Ice::Application
{
public:
virtual int run(int, char*[]);
};
int CMainServer::run(int argc, char* argv[])
{
try
{
Ice::ObjectAdapterPtr AdaptrPtr = communicator()->createObjectAdapter("SampleTest");
Ice::ObjectPtr Object = new CTest;
AdaptrPtr->add(Object, communicator()->stringToIdentity("SampleTest"));
AdaptrPtr->activate();
communicator()->waitForShutdown();
return EXIT_SUCCESS;
}
catch(const Ice::Exception ex)
{
printf("[Main]Error = %s.\n", ex);
return -1;
}
}
int main(int argc, char* argv[])
{
CMainServer app;
app.main(argc, argv, "init.config");
getchar();
return 0;
}
這里的代碼其實挺簡單的,代碼基本是固定的。
你需要的是修改CMainServer::init()方法,和在你的服務器exe路徑下,添加一個init.config的文件。這是一個配置文件,你可以把你的一些ICE配置參數寫入這個文件。
init.config里面的內容是(這是服務器的配置文件,客戶端不是這個)
SampleTest.Endpoints=tcp -p 10000
這句話的意思是,你在本機開啟一個服務,IP默認是你的服務器IP,端口是10000
下面說一下init()里面在干什么
Ice::ObjectAdapterPtr AdaptrPtr = communicator()->createObjectAdapter("SampleTest");
創建了一個對象代理。命名為SampleTest,這個名字你可以隨便起。(communicator()實際是一個ICE的智能指針)
Ice::ObjectPtr Object = new CTest;
你創建一個ICE指針對象,指向你的類。
AdaptrPtr->add(Object, communicator()->stringToIdentity("SampleTest"));
這句話是,將你的類指針,注冊到你的AdaptrPtr對象中,并關聯你的"SampleTest"。內部生成一個唯一訪問碼和你的類指針關聯。如果你有多個類,可以這樣一個個指定。
AdaptrPtr->activate();
communicator()->waitForShutdown();
return EXIT_SUCCESS;
這三句是固定的,激活你的AdaptrPtr對象,并啟動ICE服務。實際上,communicator()->waitForShutdown();會接管你的主線程。
好了,就這么多代碼,啟動你的服務器吧,如果正常,服務器會啟動并占據你的10000端口。
客戶端其實也很簡單。
客戶端的init.config文件是:
SampleTest.Proxy=SampleTest:tcp -p 10000
如果你要指定你的服務器IP,你可以
SampleTest.Proxy=SampleTest:tcp -h XXX.XXX.XXX.XXX -p 10000
如果你有多個服務器IP地址(分布網格)
SampleTest.Proxy=SampleTest:tcp -h XXX.XXX.XXX.XXX -p 10000
-h XXX.XXX.XXX.XXX -p 10000
-h XXX.XXX.XXX.XXX -p 10000
客戶端代碼也不復雜。
class CMainClient : public Ice::Application
{
public:
virtual int run(int, char*[]);
};
int CMainClient::run(int argc, char* argv[])
{
try
{
string strData = "I'm a freeeyes.";
TestICEPrx testice = TestICEPrx::checkedCast(communicator()->propertyToProxy("SampleTest.Proxy")->ice_twoway()->ice_timeout(-1)->ice_secure(false));
if(!testice)
{
printf("[CMainClient::run]testice is error.\n");
return EXIT_FAILURE;
}
int nData = testice->GetTime(strData);
printf("[CMainClient::run]GetTime is %d.\n", nData);
return EXIT_SUCCESS;
}
catch(const Ice::Exception ex)
{
printf("[Main]Error = %s.\n", ex.what());
return -1;
}
}
int main(int argc, char* argv[])
{
CMainClient app;
app.main(argc, argv, "init.config");
getchar();
return 0;
}
#include "Ice/Ice.h"

#include <string>
using namespace std;
using namespace Test;
class CTest : public TestICE
{
public:
int ping(const Ice::Current&);
int GetTime(string& strTime, const Ice::Current&);
};

這樣,一個ICE的接口對象,就和你的實際方法綁定成功了。實現么,呵呵,你可以自己去寫啦。 然后先看看服務器的源碼。

{
public:
virtual int run(int, char*[]);
};
int CMainServer::run(int argc, char* argv[])
{
try
{
Ice::ObjectAdapterPtr AdaptrPtr = communicator()->createObjectAdapter("SampleTest");
Ice::ObjectPtr Object = new CTest;
AdaptrPtr->add(Object, communicator()->stringToIdentity("SampleTest"));
AdaptrPtr->activate();
communicator()->waitForShutdown();
return EXIT_SUCCESS;
}
catch(const Ice::Exception ex)
{
printf("[Main]Error = %s.\n", ex);
return -1;
}
}
int main(int argc, char* argv[])
{
CMainServer app;
app.main(argc, argv, "init.config");
getchar();
return 0;
}




{
public:
virtual int run(int, char*[]);
};
int CMainClient::run(int argc, char* argv[])
{
try
{
string strData = "I'm a freeeyes.";
TestICEPrx testice = TestICEPrx::checkedCast(communicator()->propertyToProxy("SampleTest.Proxy")->ice_twoway()->ice_timeout(-1)->ice_secure(false));
if(!testice)
{
printf("[CMainClient::run]testice is error.\n");
return EXIT_FAILURE;
}
int nData = testice->GetTime(strData);
printf("[CMainClient::run]GetTime is %d.\n", nData);
return EXIT_SUCCESS;
}
catch(const Ice::Exception ex)
{
printf("[Main]Error = %s.\n", ex.what());
return -1;
}
}
int main(int argc, char* argv[])
{
CMainClient app;
app.main(argc, argv, "init.config");
getchar();
return 0;
}

這里面大部分代碼都是固定的,依然只是Init里面,需要修改一下。 TestICEPrx testice = TestICEPrx::checkedCast(communicator()->propertyToProxy("SampleTest.Proxy")->ice_twoway()->ice_timeout(-1)->ice_secure(false)); 這句的代碼意思是,你聲明一個TestICEPrx接口類,負責從你的init.config文件中獲取你的配置參數,去尋找SampleTest對應的接口對象。 if(!testice) { printf("[CMainClient::run]testice is error.\n"); return EXIT_FAILURE; } int nData = testice->GetTime(strData); printf("[CMainClient::run]GetTime is %d.\n", nData); 這句代碼是,如果你正確的獲得了這個對象,你就可以使用這個接口里面的內容了,具體調用方法如上。 其實,基礎的ICE還是很簡單的,隨著我自己的研究深入,希望寫出更多體會,呵呵。 代碼在ICE3.3.1和VS2005下測試通過。RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成