一个简单的聊天室的实现----ICE应用系列文章之四

原创 2006年06月08日 12:00:00
一个简单的聊天室的实现----ICE应用系列文章之四

来自whhif.cublog.cn

对于网络应用来说,比较简单就是发送请求和等待回应模型,我把这种模式称之为单工模型,服务器没有办法主动通知客户端发生了什么,只有被动的等待客户端来请求并回应,最经典的就是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
下载: 下载

ICE常见编译和运行(异常)错误

在编译和Ice应用相关的文件中,经常因为ice相关的文件包含关系而导致编译无法通过,此时的错误一般提示和handle.h相关。然而想要解决这样的错误,一般只需要把在无法编译成.o文件的.cpp文件中和...
  • zhenjing
  • zhenjing
  • 2009年09月10日 13:06
  • 13907

ICE入门之hello world

本文主要讲解ICE入门第一个hello world程序编写,内容来源于ICE官方文档。
  • wuche2010
  • wuche2010
  • 2016年12月26日 10:26
  • 490

ICE ZEROC文档翻译 (二)(Java)

ice,zeroc ice,java
  • qq_34797623
  • qq_34797623
  • 2017年12月10日 22:13
  • 35

ICE 的常见运行错误

在编译和 Ice 应用相关的文件中,经常因为 ice 相关的文件包含关系而导致编译无法通过,此时的错误一般提示和 handle.h 相关。然而想要解决这样的错误,一般只需要把在无法编译成 .o 文件的...
  • educast
  • educast
  • 2013年07月19日 11:18
  • 4255

ICE学习demo-聊天室

demo
  • bruce_wang_janet
  • bruce_wang_janet
  • 2011年03月14日 00:06
  • 3411

ICE学习(九) 客户端自动重试

参考https://doc.zeroc.com/display/Ice36/Automatic+Retries ICE客户端如果发送消息失败,可能会自动重试。这一特性非常强大。在特定环境下,这一点将...
  • kaede999
  • kaede999
  • 2018年01月22日 15:49
  • 43

一个简单的聊天室的实现----ICE应用系列文章之四

一个简单的聊天室的实现----ICE应用系列文章之四 ...
  • whhif
  • whhif
  • 2006年06月08日 12:00
  • 1403

Java Socket实现的一个简易聊天室

Java Socket实现的一个简易聊天室 大体思路:用一个ServerSocket来接收所有Client的消息,然后转发给其他Client。在Server端,每个Client对应一个ServerHa...
  • u014285517
  • u014285517
  • 2015年07月20日 17:38
  • 799

基于spring4 websocket的简易聊天室

一:创建maven webapp项目 编辑pom.xml文件
  • mn960mn
  • mn960mn
  • 2015年07月04日 18:53
  • 2040

ICE Manual(Documentation for Ice 3.5)---The Ice Run Time in Detail(Automatic Retries)

Ice may automatically retry a proxy invocation after a failure. This is a powerful feature that, whe...
  • yysct2005
  • yysct2005
  • 2013年05月07日 14:56
  • 701
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:一个简单的聊天室的实现----ICE应用系列文章之四
举报原因:
原因补充:

(最多只允许输入30个字)