CORBA/TAO使用手记1 -- C/S架构网络通信开发

CORBA/TAO使用手记1 -- C/S架构网络通信开发
转载: http://www.cppblog.com/cppx/archive/2011/02/16/140184.html

  在C/S结构的C++网络程序中,直接采用Socket API进行开发效率是很低的,所以大家发明了各种各样的网络框架,如Boost.Aiso和ACE,简化了网络通信开发的难度。
  但是这种基于数据包收发的模式还是不太方便,于是又出现了RPC、DCOM、CORBA等远程接口调用的标准。客户端只需要像调用本地函数一样调用远程接口,框架会自动处理数据包收发,请求和应答等底层细节。
  虽然现在Web技术的发展如火如荼,大有取代C/S架构应用之势,但是,直接运行于操作系统平台上的C++原生应用还是有它存在的意义,最主要的方面就是接近系统底层,对操作系统资源和底层设备的控制等,其他任何虚拟机上的中间语言是无法望其项背的。

  CORBA是一个为简化跨平台应用而提出的规范,它独立于网络协议、编程语言和软硬件平台,支持异构的分布式计算环境和不同编程语言间的对象重用。CORBA可以作为不同平台应用间信息传递的中间件,CORBA通过引入经过充分验证的有效的框架结构和通信手段,最大限度地简化了网络通信相关应用的设计与开发,使得我们可以专注于业务逻辑的实现,而无需关心通信的细节。CORBA曾在无数文章中被称作“软总线”,以表明它作为数据传递通道的基本特性。
  现在存在众多CORBA实现,既有商用的ORBacus、VisiBroker,也有一些优秀的开源实现,如:TAO、omniORB、MICO等。由于各实现遵从相同的规范,接口基本一致,所以在熟练应用一种CORBA实现后,转而使用其它实现时,一般不会存在太大的障碍。
  TAO(The ACE ORB)是美国华盛顿大学的Douglas C. Schmidt教授领导开发的一个实时CORBA平台,它是一个免费的开放源码项目,用C++语言开发,符合CORBA2.6规范。
  支持语言: C++
  支持平台: Win32,常见的各种Unix/Linux,实时操作系统如VxWorks等等。在所有的CORBA实现中,TAO支持的平台是最多的。
  支持的服务: Naming、Event、Notification、Security、Time、Scheduling、Logging、Lifecycle、Trading、Concurrency、Lifecycle、A/V Streaming、Load balancing等。

  在日常工作中我们经常使用的服务就是Naming服务和Notification服务了。Naming服务让你可以把自己的远程对象注册到一个索引服务中,使用者通过友好的注册名即可找到提供服务的对象,而不用关心这个对象运行在那台机器上。Notification服务给客户端提供了主动推送消息的机制,而不需要客户端不断查询是否有自己感兴趣的消息。
  那么在CORBA中客户端和服务端通过什么方式约定双方的通讯协议呢?这就是IDL语言的功劳了,IDL以一种通用的方式为C/S双方提供了接口的描述,语法非常类似于C++或Java的类的描述。CORBA提供了专门的工具用来把IDL语言编写的接口文件编译成C++或Java能够理解的桩和框架类,服务端基于IDL编译器生成的“框架”添加服务实现,客户端调用IDL编译器生成的“桩”调用远程服务的接口,双方都不需要关心对方内部如何实现,通信数据包格式等问题,IDL会为你搞定一切。
  百闻不如一见,通过一个真实的IDL文件例子,看一下接口的定义到底是如何工作的:  

 1  #ifndef ScriptManageService_h__
 2  #define  ScriptManageService_h__
 3 
 4  #include  " ALEE_ScriptManageDefines.idl "
 5 
 6  module alee {
 7  module ScriptManage {
 8 
 9       //////////////////////////////////////////////////////////////////////// //
10       //  脚本管理服务
11       //////////////////////////////////////////////////////////////////////// //
12       interface  ALEE_ScriptManageService {
13 
14           //  获取事件类型列表
15          boolean apiGetEventTypes(  out  EventTypeList_t list );
16 
17           //  列出所有脚本
18          boolean apiGetScriptList(  out  ScriptList_t list);
19 
20           //  获取脚本信息
21          boolean apiGetScriptInfo(  in   long  ID,  out  ScriptInfo_t info );
22 
23           //  保存脚本,ID>0时修改,ID=0时新增,返回新增的ID或原有ID
24          boolean apiSetScriptInfo(  in   long  ID,  in  ScriptInfo_t info );
25 
26           //  删除脚本
27          boolean apiDeleteScript(  in   long  ID );
28      };
29 
30  };
31  };
32 
33  #endif   //  ScriptManageService_h__
34 

  从这个IDL文件中可以看出,这个名为“脚本管理服务”的接口interface ALEE_ScriptManageService中定义了5个方法,调用IDL编译器编译后,生成了下面的6个文件,其中前3个是客户端的“桩”,后3个是服务端的“框架”。

  然后,就需要我们来实现服务端的接口了,在ALEE_ScriptManageServiceS.h文件中IDL编译器生成了一个C++的类class ALEE_ScriptManageService,其中包含的几个纯虚函数就是我们定义的IDL接口方法。

 1  namespace  POA_alee
 2  {
 3     namespace  ScriptManage
 4    {
 5       class  UBISALEE_API ALEE_ScriptManageService
 6        :  public   virtual  PortableServer::ServantBase
 7      {
 8       protected :
 9        ALEE_ScriptManageService ( void );
10      
11       public :
12        ALEE_ScriptManageService ( const  ALEE_ScriptManageService &  rhs);
13         virtual   ~ ALEE_ScriptManageService ( void );
14        
15         virtual  ::CORBA::Boolean apiGetEventTypes (::alee::ScriptManage::EventTypeList_t_out list)  =   0 ;
16         virtual  ::CORBA::Boolean apiGetScriptList (::alee::ScriptManage::ScriptList_t_out list)  =   0 ;
17         virtual  ::CORBA::Boolean apiGetScriptInfo (::CORBA::Long ID,::alee::ScriptManage::ScriptInfo_t_out info)  =   0 ;
18         virtual  ::CORBA::Boolean apiSetScriptInfo (::CORBA::Long ID, const  ::alee::ScriptManage::ScriptInfo_t  &  info)  =   0 ;
19         virtual  ::CORBA::Boolean apiDeleteScript (::CORBA::Long ID)  =   0 ;
20      };
21    }  //  module alee::ScriptManage
22  //  module alee
23 

  我们要实现这个接口,就需要添加一个子类继承这个接口类:
 1 
 2  class  ALEE_ScriptManageService_i :  public  POA_alee::ScriptManage::ALEE_ScriptManageService
 3  {
 4      ORB_Objects  &        m_orb;
 5      ALEE_DataBase_Impl  & m_dat;
 6      ALEE_ScriptList_t  &  m_scripts;
 7 
 8  public :
 9      ALEE_ScriptManageService_i(ORB_Objects  & orb,ALEE_DataBase_Impl  & dat,ALEE_ScriptList_t  &  scripts);
10       ~ ALEE_ScriptManageService_i( void );
11 
12       virtual  CORBA::Boolean apiGetEventTypes(EventTypeList_t_out list);
13       virtual  CORBA::Boolean apiGetScriptList(ScriptList_t_out list);
14       virtual  CORBA::Boolean apiGetScriptInfo(CORBA::Long ID,ScriptInfo_t_out info);
15       virtual  CORBA::Boolean apiSetScriptInfo(CORBA::Long ID, const  ScriptInfo_t  &  info);
16       virtual  CORBA::Boolean apiDeleteScript (CORBA::Long ID);
17  };
18 

  具体实现方法不必多言,就像写一个普通的C++类一样即可。我们关心的问题是服务类写好了,客户端如何知道这个类在哪里?
  下面就需要把我们的接口实现注册到Naming服务中,ORB_Objects类是一个ORB对象的封装类,是为了方便而把ORB下文相关的对象都放在了一起,暂时把它当成是个ORB的句柄,负责与软总线ORB通讯即可。
 1 
 2  #define  SERVICE_NAME "ALEE_ScriptManageService"
 3 
 4  ALEE_ScriptManageService_i::ALEE_ScriptManageService_i(ORB_Objects  &         orb,
 5                                                         ALEE_DataBase_Impl  &  dat,
 6                                                         ALEE_ScriptList_t  &   scripts) :
 7  m_orb(orb),
 8  m_dat(dat),
 9  m_scripts(scripts)
10  {
11      m_orb.rebind_name(SERVICE_NAME,_this());
12  }
13 
  m_orb是在服务端启动时初始化的一个ORB_Objects实例,在创建“脚本管理服务”时通过构造函数传入了一个引用,在服务类实例化时,调用m_orb把自己注册到Naming服务里,这样客户端就可以通过访问名字服务知道我们的服务所在的位置。

  上手了CORBA之后,才发现自己原来设想的 C++实现远程服务对象调用( http://www.cppblog.com/cppx/archive/2009/07/22/90820.html)实在是原始而又弱智的梦呓。
  先写到这里吧,关于客户端调用的方法,下回分解! 

你可能感兴趣的:(框架,网络,脚本,database,语言,编译器)