Lucine

厚德载物,自强不息!

常用链接

统计

最新评论

转载:C/S架构网络通信开发

  在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)实在是原始而又弱智的梦呓。
  先写到这里吧,关于客户端调用的方法,下回分解!

posted on 2011-02-17 12:16 Lucine 阅读(930) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理