8.1客户端配置
客户需要执行以下步骤来配置双向连接:
1)创建一个对象适配器接收回调请求。该适配器不需要设置端点,如果它唯一的目的仅仅是在双向连接上接收回调。
2)使用对象适配器注册回调对象。
3)激活对象适配器。
4)代理对象调用ice_getconnection函数,获得连接对象。
5)用获得的连接对象,调用setadapter函数,传递给回调对象适配器。
6)向服务器传递回调对象的身份identity。
下面C++代码(客户端)说明了这些步骤:
Ice::ObjectAdapterPtr adapter = communicator >createObjectAdapter("CallbackAdapter");
Ice::Identity ident;
ident.name = IceUtil::generateUUID();
ident.category = "";
adapter >add(new CallbackI, ident);
adapter >activate();
proxy >ice_getConnection() >setAdapter(adapter);
proxy >addClient(ident);
8.2服务器配置
双向连接实现回调:
1)获得回调对象的身份identity,这个identity通常是由客户端提供的。
2)在连接器上调用函数createproxy,为回调对象创建一个代理。
这些步骤是在C + +(服务端)代码,如下所示:
void addClient(const Ice::Identity& ident, const Ice::Current& curr)
{
CallbackPrx client = CallbackPrx::uncheckedCast(curr.con >createProxy(ident));
client >notify();
}
8.3局限性
双向连接有一定的局限性:
1)它们只能配置为面向连接的传输,如TCP和SSL。
2)大多数代理工厂的方法,与一个连接器创建的代理(createproxy)操作是不相关的。
这个代理(createproxy)绑定到一个现有的连接器上,因此代理反映连接的配置。例如,它是不可能去改变这样的代理超时值,否则导致异常FixedProxyException。
3)双向连接不兼容ACM(Active Connection Management)。
8.4线程的考虑
ICE运行期间为了处理网络连接通信,通常创建两个线程池:客户端的线程池管理输出(outgoing)连接;服务器的线程池管理输入(incoming)连接。服务器上的所有对象适配器默认共享相同的线程池,但一个对象适配器也可以配置它自己的线程池。客户端和服务器的线程池的大小是1个。
服务器的线程池通常分配客户端的请求。如果服务器使用一个双向连接发送回调请求,那么服务器线程池还必须处理答复这些请求。
如果您需要均衡平行多个调度请求的能力,您必须增加适当的线程池大小;或如果您需要进行双向嵌套调用。例如,在一个双向连接上,一个客户端接收回调请求,嵌套调用必须增加客户的线程池大小。详细内容参考ICE嵌套调用的更多信息,并了解在ice上的线程模型细节。
8.6例子
下面例子演示了如何配置一个双向连接。您可以使用“netstat –an”命令来查看网络连接状态:双向连接只产生一个TCP连接。
regManager作为会话工厂(sessionFactory),为客户端连接时申请regAgent会话(session)对象。EventHandler作为服务端的回调对象,用来通知客户端。
regManager和regAgent实现过程放在服务器端,EventHandler实现过程放在客户端。
本章节例子只描述了双向连接过程,其他接口代码未实行。
8.6.1定义接口文件
#ifndef _CLOUDDAQSERVICE_ICE_
#define _CLOUDDAQSERVICE_ICE_
//
// version 1.0.0
//
#include <Ice/Identity.ice>
module CloudDaqService
{
struct pointStream
{
string pointcode;
byte type;
float value;
};
sequence <pointStream> pointStreamSeq;
sequence <byte> byteSeq;
struct eventStream
{
byte type;
byteSeq value;
};
// This exception is raised every time a failure or error is
// detected in a treatment.
exception GeneralException
{
string reason;
};
interface EventHandler
{
void onNotify(eventStream event);
// @interface: EventHandler
// @method : alive
// @purpose : test is the EventHandler is again instantiate and
// so if daq communication part is running
// if the call of the method pass, EventHandler is alive;
// else Ice send an exception StateClosed.
void alive();
};
interface RegAgent
{
void hello() throws GeneralException;
bool write(pointStream data) throws GeneralException;
bool bulkWrite(pointStreamSeq datum) throws GeneralException;
pointStreamSeq getPointsValue() throws GeneralException;
void setEventHandler(EventHandler *handler) throws GeneralException;
EventHandler *getEventHandler() throws GeneralException;
};
interface RegManager
{
RegAgent *createInterface(string user, Ice::Identity ident);
void deleteInterface(string user);
};
};
#endif
//
// EOF clouddaqservice.ice
//
8.6.2服务端实现代码
1) regmanagerimp.h和regmanagerimp.cpp
#ifndef _REGMANAGERIMP_H
#define _REGMANAGERIMP_H
#include <clouddaqservice.h>
#include <regagentImp.h>
using namespace std;
typedef map<string, RegAgentImp *> RegAgentMap;
class RegManagerImp : public CloudDaqService::RegManager, public IceUtil::Mutex
{
public:
virtual CloudDaqService::RegAgentPrx createInterface(const string& user, const ::Ice::Identity&, const ::Ice::Current&);
virtual void deleteInterface(const string& user, const ::Ice::Current&);
public:
void onNotify(const CloudDaqService::eventStream& event);
void alive();
bool checkAgent();
const int getAgentSize();
private:
RegAgentMap RegagentMap_;
};
#endif // _REGMANAGERIMP_H
#include <IceUtil/IceUtil.h>
#include <Ice/Ice.h>
#include <regmanagerimp.h>
CloudDaqService::RegAgentPrx RegManagerImp::createInterface(const string& user, const ::Ice::Identity& ident, const ::Ice::Current& Current)
{
Lock sync(*this);
//assert(user != NULL && strlen(user) > 0);
RegAgentMap::iterator i;
if ((i = RegagentMap_.find(user)) != RegagentMap_.end())
{
const string key = (*i).first;
RegAgentImp* pAgent = (*i).second;
CloudDaqService::RegAgentPrx regAgent = CloudDaqService::RegAgentPrx::uncheckedCast(Current.adapter->addWithUUID(pAgent));
return regAgent;
}
RegAgentImp *pAgent = new RegAgentImp();
CloudDaqService::RegAgentPrx regAgent;
regAgent = CloudDaqService::RegAgentPrx::uncheckedCast(Current.con->createProxy(ident));
RegagentMap_[user] = pAgent;
return regAgent;
}
void RegManagerImp::deleteInterface(const string& user, const ::Ice::Current&)
{
Lock sync(*this);
//assert(user != NULL);
RegAgentMap::iterator i;
for (i = RegagentMap_.begin(); i != RegagentMap_.end(); i++)
{
const string key = (*i).first;
const char *val = (const char *)key.c_str();
RegAgentImp* pAgent = (*i).second;
if (strcmp(val, user.c_str()) == 0)
{
pAgent->destroy();
RegagentMap_.erase(i);
return;
}
}
}
void RegManagerImp::onNotify(const CloudDaqService::eventStream& event)
{
Lock sync(*this);
RegAgentMap::iterator i;
if (getAgentSize() <= 0)
{
return;
}
for (i = RegagentMap_.begin(); i != RegagentMap_.end(); i++)
{
const std::string key = (*i).first;
RegAgentImp* pAgent = (*i).second;
if (pAgent && !pAgent->checkException())
{
::CloudDaqService::eventStream event;
event.type = 1;
pAgent->onNotify(event);
}
}
}
void RegManagerImp::alive()
{
Lock sync(*this);
RegAgentMap::iterator i;
if (getAgentSize() <= 0)
{
return;
}
for (i = RegagentMap_.begin(); i != RegagentMap_.end(); i++)
{
const std::string key = (*i).first;
RegAgentImp* pAgent = (*i).second;
if (pAgent && !pAgent->checkException())
{
pAgent->alive();
}
}
}
bool RegManagerImp::checkAgent()
{
Lock sync(*this);
bool bRet = false;
if (getAgentSize() <= 0)
{
return bRet;
}
RegAgentMap::iterator j = RegagentMap_.begin();
RegAgentMap::iterator last = RegagentMap_.end();
while (j != last)
{
const std::string key = (*j).first;
RegAgentImp* pAgent = (*j).second;
if (pAgent && pAgent->checkException())
{
pAgent->destroy();
RegagentMap_.erase(j);
bRet = true;
break;
}
++j;
}
return bRet;
}
const int RegManagerImp::getAgentSize()
{
return RegagentMap_.size();
}
2) regagentimp.h和regagentimp.cpp
#ifndef _REGMANAGENTIMP_H
#define _REGMANAGENTIMP_H
#include <clouddaqservice.h>
using namespace std;
class RegAgentImp : public CloudDaqService::RegAgent
{
public:
RegAgentImp();
virtual ~RegAgentImp();
public:
virtual void hello(const ::Ice::Current&);
virtual bool write(const ::CloudDaqService::pointStream&, const ::Ice::Current&);
virtual bool bulkWrite(const ::CloudDaqService::pointStreamSeq&, const ::Ice::Current&);
virtual ::CloudDaqService::pointStreamSeq getPointsValue(const ::Ice::Current&);
virtual void setEventHandler(const ::CloudDaqService::EventHandlerPrx&, const ::Ice::Current&);
virtual ::CloudDaqService::EventHandlerPrx getEventHandler(const ::Ice::Current&);
public:
void onNotify(const ::CloudDaqService::eventStream &event);
void alive();
void destroy(void);
bool checkException();
private:
::CloudDaqService::EventHandlerPrx Controller_;
bool bException_;
};
#endif // _REGMANAGENTIMP_H
#include <IceUtil/IceUtil.h>
#include <Ice/Ice.h>
#include <regagentimp.h>
RegAgentImp::RegAgentImp()
{
bException_ = false;
}
RegAgentImp::~RegAgentImp()
{
}
void RegAgentImp::hello(const ::Ice::Current&)
{
cout << "Hello World!" << endl;
}
bool RegAgentImp::write(const ::CloudDaqService::pointStream&, const ::Ice::Current&)
{
return true;
}
bool RegAgentImp::bulkWrite(const ::CloudDaqService::pointStreamSeq&, const ::Ice::Current&)
{
return true;
}
::CloudDaqService::pointStreamSeq RegAgentImp::getPointsValue(const ::Ice::Current&)
{
::CloudDaqService::pointStreamSeq seq;
return seq;
}
void RegAgentImp::setEventHandler(const ::CloudDaqService::EventHandlerPrx& eventHander, const ::Ice::Current&)
{
Controller_ = eventHander;
}
::CloudDaqService::EventHandlerPrx RegAgentImp::getEventHandler(const ::Ice::Current&)
{
return Controller_;
}
void RegAgentImp::onNotify(const ::CloudDaqService::eventStream &event)
{
try
{
Controller_->onNotify(event);
}
catch (const Ice::Exception& ex)
{
cerr << ex << endl;
bException_ = true;
}
}
void RegAgentImp::alive()
{
try
{
Controller_->alive();
}
catch (const Ice::Exception& ex)
{
cerr << ex << endl;
bException_ = true;
}
}
bool RegAgentImp::checkException()
{
return bException_;
}
void RegAgentImp::destroy()
{
}
3) demoserver.h和demoserver.cpp
#include <ice/ice.h>
#include <regmanagerimp.h>
using namespace std;
using namespace CloudDaqService;
class RefreshTask : public IceUtil::TimerTask
{
public:
RefreshTask(const Ice::LoggerPtr& logger, RegManagerImp* regManager) :
_logger(logger), regManager_(regManager)
{
}
virtual void runTimerTask()
{
try
{
regManager_->alive();
}
catch (const Ice::Exception& ex)
{
Ice::Warning warn(_logger);
warn << "RefreshTask: " << ex;
}
}
private:
const Ice::LoggerPtr _logger;
RegManagerImp *regManager_;
};
class CloudDaqServer : public Ice::Application
{
public:
virtual int run(int, char*[]);
private:
IceUtil::TimerPtr timer_;
};
int
main(int argc, char* argv[])
{
CloudDaqServer app;
return app.main(argc, argv);
}
int
CloudDaqServer::run(int argc, char*[])
{
Ice::CommunicatorPtr ic = communicator();
Ice::ObjectAdapterPtr adapter = ic->createObjectAdapterWithEndpoints("CloudDaqAdapter", "default -p 10000");
RegManagerImp *pManager = new RegManagerImp;
CloudDaqService::RegManagerPtr regManager = pManager;
adapter->add(regManager, communicator()->stringToIdentity("CloudDaq"));
adapter->activate();
timer_ = new IceUtil::Timer();
timer_->scheduleRepeated(new RefreshTask(communicator()->getLogger(), pManager), IceUtil::Time::seconds(5));
communicator()->waitForShutdown();
return EXIT_SUCCESS;
}
8.6.3客户端实现代码
#include <Ice/Ice.h>
#include <IceUtil/UUID.h>
#include <eventhandlerimp.h>
using namespace std;
using namespace CloudDaqService;
class CloudDaqClient : public Ice::Application
{
public:
CloudDaqClient();
virtual int run(int, char*[]);
private:
void menu();
};
int
main(int argc, char* argv[])
{
CloudDaqClient app;
return app.main(argc, argv);
}
//
// Since this is an interactive demo we don't want any signal
// handling.
//
CloudDaqClient::CloudDaqClient() :
Ice::Application(Ice::NoSignalHandling)
{
}
int
CloudDaqClient::run(int argc, char* argv[])
{
if (argc > 1)
{
cerr << appName() << ": too many arguments" << endl;
return EXIT_FAILURE;
}
Ice::CommunicatorPtr ic = communicator();
Ice::ObjectPrx base = ic->stringToProxy("CloudDaq:default -h 192.168.11.100 -p 10000");
CloudDaqService::RegManagerPrx regManager = RegManagerPrx::checkedCast(base);
if (!regManager)
{
cerr << argv[0] << ": invalid proxy" << endl;
return EXIT_FAILURE;
}
menu();
::CloudDaqService::RegAgentPrx regAgent = nullptr;
char c;
do
{
try
{
cout << "==> ";
cin >> c;
if (c == 'c' && !regAgent)
{
Ice::Identity ident;
ident.name = IceUtil::generateUUID();
ident.category = "";
Ice::ObjectAdapterPtr adapter = ic->createObjectAdapter("");
EventHandlerPtr cb = new EventHandlerImp;
adapter->add(cb, ident);
adapter->activate();
regManager->ice_getConnection()->setAdapter(adapter);
regAgent = regManager->createInterface("guest", ident);
}
else if (c == 'h' && regAgent)
{
regAgent->hello();
}
else if (c == 'x')
{
// Nothing to do
}
else if(c == '?')
{
menu();
}
else
{
cout << "unknown command `" << c << "'" << endl;
menu();
}
}
catch (const Ice::Exception& ex)
{
cerr << ex << endl;
}
}
while (cin.good() && c != 'x');
return EXIT_SUCCESS;
}
void
CloudDaqClient::menu()
{
cout <<
"usage:\n"
"c: create agent interface by user\n"
"h: send hello to server\n"
"x: exit\n"
"?: help\n";
}
9 总结
本文主要简单介绍了几种常见的函数调用方法,并以一些已经测试通过的例子来说明各种调用方法。其中可能需要关注的是回调函数、双向连接和异步调用(AMI和AMD)使用情况。因ICE牵涉的内容很多,具体细节见官方网站完整说明。