ICE专题:ICE实现聊天室

对于网络应用来说,比较简单就是发送请求和等待回应模型,我把这种模式称之为单工模型,服务器没有办法主动通知客户端发生了什么,只有被动的等待客户端来请求并回应,最经典的就是HTTP服务,对于这种模型来说这已经够了,但对于服务器与客户之间的互动来说,这种就不行了,得需要双工模型,即服务器与客户之间的相互通知。对于这种模型,最能说明问题的就是一个聊天室了,一个房间有多人聊天,一个人所说的话得经过服务器而通知其它人,这种就需要服务器与客户端的一个简单互动了,但这也足以说明问题了。ICE的出现使这种模型变得简单,下面我就来介绍一下如何使用ICE来开发聊天室。

如上图所述,我们所要做的工作就是将一台客户端发出的信息,广播到其它的客户端上,就是这么一个简单的操作。为了达到这种目的,必须在服务器端和客户端都开一个监听端口,用来双方交互,同时服务器端还要接受客户端的请求,成为一个信息HUB。

因为ICE本身就是平台无关的,所以在什么平台上编缉并不影响其它平台。首先要写一个slice文件,定义服务。

module FloorSpace

{

interface CallBack

{

void GetInput(string content);

};

dictionary<string,CallBack *> CacheMap;

interface Floor

{

bool Register(string name);

void SetInput(string content);

void Unregister();

void SetupCallback(CallBack * cp);

};

};

CallBack是用来定义客户端的回调服务,Floor是用来定义服务器端的服务。

定义好slice文件后,比如叫做floor.ice,用slice2cpp floor.ice生成服务。它会生成floor.h 和floor.cpp两个文件,这两个文件定了服务接口和代理接口。

需要一个文件用来从floor.h中继承Floor接口中的各种服务,需要一个文件用来从floor.h中继承CallBack接口中的服务。

class FloorI:virtual public Floor

{

virtual bool Register(const string & name,const Current & context);

virtual void SetInput(const string & content,const Current & context);

virtual void Unregister(const Current & context);

virtual void SetupCallback(const CallBackPrx & prx,const Current & context);

CacheMap m_cache_map;

};

class CallBackI:virtual public CallBack

{

public:

virtual void GetInput(const string & content,const Current & context);

};

当然需要将FloorI中的虚函数实现,这就是你的服务真正所在了。

bool FloorI::Register(const string & name,const Current & context)

{

if(m_cache_map.find(name)!=m_cache_map.end())

return 0;

else

m_cache_map[name];

return 1;

}

void FloorI::Unregister(const Current & context)

{

Context::const_iterator q=context.ctx.find("user_name");

if(q!=context.ctx.end())

{

CacheMap::iterator p;

if((p=m_cache_map.find(q->second))!=m_cache_map.end())

m_cache_map.erase(p);

}

}

void FloorI::SetupCallback(const CallBackPrx & prx,const Current & context)

{

Context::const_iterator p=context.ctx.find("user_name");

if(p!=context.ctx.end())

{

m_cache_map[p->second]=prx;

}

}

void FloorI::SetInput(const string & content,const Current & context)

{

Context::const_iterator q=context.ctx.find("user_name");

if(q!=context.ctx.end())

{

CacheMap::iterator p;

for(p=m_cache_map.begin();p!=m_cache_map.end();++p)

{

if(p->first!=q->second)

{

Context ctx;

ctx["user_name"]=q->second;

try

{

p->second->GetInput(content,ctx);

}

catch(ConnectionRefusedException e)

{

m_cache_map.erase(p);

cout<<" 挂了"<<endl;

}

catch(NullHandleException e)

{

m_cache_map.erase(p);

cout<<" 没有诚意"<<endl;

}

}

}

}

}

CallBack服务具体定义:

void CallBackI::GetInput(const string & content,const Current & context)

{

Context::const_iterator q=context.ctx.find("user_name");

if(q!=context.ctx.end())

{

cout<<"["<<q->second<<" say]"<<content<<endl;

}

}

这样我们的聊天室服务器端和客户端的服务定义实现完毕。剩下就是写服务器和客户端了,服务器的实现很简单,因为这是ICE的框架:

int ServerApp::run(int argc,char * argv[])

{

shutdownOnInterrupt();

ObjectAdapterPtr adapter=communicator()->createObjectAdapter("Floor.Server");

adapter->add(new FloorI,stringToIdentity("floor"));

adapter->activate();

communicator()->waitForShutdown();

return EXIT_SUCCESS;

}

就这么几行代码,可以实现网络联结和服务创建。客户端的实现:

int ClientApp::run(int argc,char * argv[])

{

shutdownOnInterrupt();

Ice::PropertiesPtr properties = communicator()->getProperties();

const char * buf="Floor.Proxy";

string proxy=properties->getProperty(buf);

if(proxy.empty())

{

cerr << argv[0] << ": property `" << buf << "' not set" << endl;

return EXIT_FAILURE;

}

cout<<proxy<<endl;

FloorPrx floorprx=FloorPrx::checkedCast(communicator()->stringToProxy(proxy));

if(!floorprx)

{

cerr << argv[0] << ": invalid proxy" << endl;

return EXIT_FAILURE;

}

string user_name;

cout<<"name : ";

cin>>user_name;

cout<<endl;

if(floorprx->Register(user_name)==0)

{

cout<<user_name<<" has been registered"<<endl;

return EXIT_FAILURE;

}

Ice::ObjectAdapterPtr adapter = communicator()->createObjectAdapter("Floor.Client");

adapter->add(new CallBackI, Ice::stringToIdentity("callbackReceiver"));

adapter->activate();

Context ctx;

ctx["user_name"]=user_name;

floorprx=FloorPrx::uncheckedCast(floorprx->ice_newContext(ctx));

CallBackPrx cbp=CallBackPrx::uncheckedCast(adapter->createProxy(stringToIdentity("callbackReceiver")));

floorprx->SetupCallback(cbp);

string content;

cout<<"please input something"<<endl;

cout<<"["<<user_name<<" say]";

while(cin>>content)

{

cout<<endl;

floorprx->SetInput(content);

cout<<"["<<user_name<<" say]";

}

floorprx->Unregister();

}

实现的就是一个人说话,将他说的话传到服务器,服务器将其广播到其它用户,功能实现完毕。

总结:ICE使你不用关心网络如何联结,端口如何定义,你所要关心的就是服务如何实现,而这正是你想要的。当你知道想做什么,但一想到网络通讯的复杂程度,可能就没有信心了,ICE正好使它成为可能。学习ICE是一件很愉快的事。

文件:
ice_floor_callback.rar

大小:
10KB

下载:
下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
ICE-3.7.4 最新安装文件msi文件,windows版 ICE常见报错 Exception in thread Ice.ConnectionRefusedException error = 0 at IceInternal.Network.doFinishConnect(Network.java:417) at IceInternal.TcpTransceiver.initialize(TcpTransceiver.java:33) at Ice.ConnectionI.initialize(ConnectionI.java:1536) at Ice.ConnectionI.socketReady(ConnectionI.java:1116) at Ice.ConnectionI$SocketReadyCallback.socketReady(ConnectionI.java:2299) at IceInternal.SelectorThread.run(SelectorThread.java:203) at IceInternal.SelectorThread$HelperThread.run(SelectorThread.java:273) Caused by: java.net.ConnectException: Connection refused at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:574) at IceInternal.Network.doFinishConnect(Network.java:393) ... 6 more 这种报错是ICE服务端没有起来,telnet服务端ICE的端口不通,无法建立socke 原帖地址:http://blog.csdn.net/zhenjing/archive/2009/09/10/4538705.aspx ICE常见编译和运行(异常)错误 收藏 在编译和Ice应用相关的文件中,经常因为ice相关的文件包含关系而导致编译无法通过,此时的错误一般提示和handle.h相关。然而想要解决这样的错误,一般只需要把在无法编译成.o文件的.cpp文件中和ice文件相关的头文件放在该.cpp文件的起始行即可。也就是说,根据提示,把.cpp文件中最早提示导致出错的.h文件放在起始行。 ICE的常见运行错误(异常): 1 使用的地址错误,IP并非本地IP: 发生在初始化服务器时,没办法初始化adapter. 错误信息: (IP错误) ./test: Network.cpp:475: Ice::SocketException: socket exception: Cannot assign requestedaddress 另外: 已经启动服务器后又重新启动: 发生在初始化服务器时,没办法初始化adapter. 错误信息: (port已经被使用) ./server: Network.cpp:475:Ice::SocketException: socket exception: Address already in use ///stringtoProxy对于任何string都是有效的,均可以生成相应代理,但是该代理是否有效是无法保证的. 如果代理无效,也就是说根本就没有这样的adapter或者对象,那么使用Checkcast或直接用该代理调用相应对象接口均会抛异常. 下面对每种情况加于分析. 2 使用的代理IP错误: 发生在使用代理调用接口的时候 原因: 根本就没有相应的通讯器存在. 错误信息: (使用的代理IP错误) 抛出异常: Ice::ConnectFailedException(需要几秒, 需要进行搜索) 3 使用的代理端口错误,两边不一致 : 发生在使用代理调用接口的时候 原因: 存在通讯器,但是不存在相应的对象适配器. 错误信息: 抛出异常: Ice::ConnectionRefusedException(很快, 端口没有被启用引起的,无人监听该端口) 4 使用的对象名字不正确: 发生在使用代理调用接口的时候 原因: 能够找到相应的对象适配器,但是该对象适配器中无法找到相应的对象 错误信息: 抛出异常: Ice::ObjectNotExistException(很
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stoneson

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值