跟我從頭學TAO編程系列(3) -- 通過實例學習CORBA核心概念

跟我從頭學TAO編程系列

通過實例學習CORBA核心概

Stone Jiang [email protected]

http://www.ace-tao.org

 

本系列的第一篇我們學會了怎麼下載和編譯ACE,TAO第二篇我們編寫了最簡單的TAO應用程序。學習CORBA,TAO與學習其它學科一樣,一定要掌握其核心概念。這了節,我們通過第二篇的實例來學習CORBA的核心概念。

 

1.CORBA架構

CORBA的架構如下圖:

image

2. CORBA核心概念

 

2.1 CORBA Object

CORBA對象是一個“虛擬”的實體。它可以被ORB定位和被客戶端調用。在上一篇示例中,

interface Hello即爲corba對象, 定義在Hello.idl中

//@file:   Test.idl
//@author: StoneJiang<[email protected]>
//@ref :  http://www.ace-tao.org

/// Put the interfaces in a module, to avoid global namespace pollution
module Test
{
  /// A very simple interface
  interface Hello
  {
    /// Return a simple string
    string get_string ();

    /// A method to shutdown the ORB
    /**
     * This method is used to simplify the test shutdown process
     */
    oneway void shutdown ();
  };
};

 

CORBA對象並不真實存在,它只存在於概念中。因此,CORBA對象需要程序員用編程語言把它實現。

 

2.2 client,object reference, request,stub

在本例在,client指client.exe。它是發起請求的程序。它的代碼片如下

#include "TestC.h"

int
ACE_TMAIN(int argc, ACE_TCHAR *argv[])
{
   CORBA::ORB_var orb = CORBA::ORB_init (argc, argv);

   CORBA::Object_var tmp = orb->string_to_object("file://test.ior");

   Test::Hello_var hello = Test::Hello::_narrow(tmp.in ());

   CORBA::String_var the_string = hello->get_string ();

    ACE_DEBUG ((LM_DEBUG, "(%P|%t) - string returned <%C>/n",
                  the_string.in ()));

  return 0;
}

其中,對象引用(object reference,)此處是與字符串file://test.ior表示的;

發起的請求(request)爲

CORBA::String_var the_string = hello->get_string ();

本例中的調用,採用的是static stub方式,與static stub相對的還有另一種調用方式DII,這裏我們暫不講述。我們可以把

TestC.h,TestC.cpp 文件視爲 stub,它是由tao_idl.exe編譯hello.idl時生成的文件。

 

 

2.2 target object, server, servant,,orb,poa

 

下面是HelloS.h的片斷

class Hello;
typedef Hello *Hello_ptr;

class  Hello
  : public virtual PortableServer::ServantBase
{
protected:
  Hello (void);

public:
  // Useful for template programming.
  typedef ::Test::Hello _stub_type;
  typedef ::Test::Hello_ptr _stub_ptr_type;
  typedef ::Test::Hello_var _stub_var_type;
  Hello (const Hello& rhs);
  virtual ~Hello (void);
  ::Test::Hello *_this (void);
 
  virtual char * get_string (
      void) = 0;
   virtual void shutdown (
      void) = 0;
 
};

其中, get_string()和shutdown()兩個成員函數,被定義爲純虛函數(如果對純虛函數的概念缺少了解,請參考C++相關知識),這也表示,類Hello是一個抽象類,必須由派生類重載這兩個函數。這個派生類稱爲servant。在本例在,servant由Hello.h來定義,由Hello.cpp來實現。

下面是服務端的代碼片斷

#include "TestS.h"

/// Implement the Test::Hello interface
class Hello
  : public virtual POA_Test::Hello
{
public:
  /// Constructor
  Hello (CORBA::ORB_ptr orb);

  // = The skeleton methods
  virtual char * get_string (void);

  virtual void shutdown (void);

private:
  /// Use an ORB reference to convert strings to objects and shutdown
  /// the application.
  CORBA::ORB_var orb_;
};

 

 

 

這裏的文件TestS.h及TestS.cpp,也是由tao_idl.exe編譯Hello.idl時生成的文件,這兩個文件用於服務端,它就是skeleton。請參考CORBA構架圖查看skeleton所在的位置。

 

 

#include "Hello.h"

int
ACE_TMAIN(int argc, ACE_TCHAR *argv[])
{
  try
    {
      CORBA::ORB_var orb =
        CORBA::ORB_init (argc, argv);

     CORBA::Object_var poa_object =
        orb->resolve_initial_references("RootPOA");

      PortableServer::POA_var root_poa =
        PortableServer::POA::_narrow (poa_object.in ());

      if (CORBA::is_nil (root_poa.in ()))
        ACE_ERROR_RETURN ((LM_ERROR,
                           " (%P|%t) Panic: nil RootPOA/n"),
                          1);

      PortableServer::POAManager_var poa_manager = root_poa->the_POAManager ();
      if (parse_args (argc, argv) != 0)
        return 1;
     poa_manager->activate ();

      Hello *hello_impl = 0;
      ACE_NEW_RETURN (hello_impl,
                      Hello (orb.in ()),
                      1);

      PortableServer::ServantBase_var owner_transfer(hello_impl);

      PortableServer::ObjectId_var id =
        root_poa->activate_object (hello_impl);

      CORBA::Object_var object = root_poa->id_to_reference (id.in ());

      Test::Hello_var hello = Test::Hello::_narrow (object.in ());

      CORBA::String_var ior = orb->object_to_string (hello.in ());

      // Output the IOR to the <ior_output_file>
      FILE *output_file= ACE_OS::fopen (ior_output_file, "w");
      if (output_file == 0)
        ACE_ERROR_RETURN ((LM_ERROR,
                           "Cannot open output file for writing IOR: %s/n",
                           ior_output_file),
                           1);
      ACE_OS::fprintf (output_file, "%s", ior.in ());
      ACE_OS::fclose (output_file);

      ACE_DEBUG ((LM_DEBUG, "(%P|%t) server - wait for requsting from client./n"));

      orb->run ();

      ACE_DEBUG ((LM_DEBUG, "(%P|%t) server - event loop finished/n"));

      root_poa->destroy (1, 1);

      orb->destroy ();
    }
  catch (const CORBA::Exception& ex)
    {
      ex._tao_print_exception ("Exception caught:");
      return 1;
    }

  return 0;
}

 

 

服務端的執行過程如下 (用顏色來對應代碼)

1) 初始化orb

2) 解析poa

3) 獲得poa管理器,並激活它。 poa是主動對象(有關主動對象,請參考ACE_Task以及POSA),它相當於在自己的線程在運行。

4) 創建corba對象的servant

5) 用poa激活corba對象

6) 將corba對象的引用字符串化,並保存在磁盤上,供客戶端使用。

7) 運行orb的事件循環,等待客戶端的連接

8) 結束事件循環後,銷燬poa以及orb

orb由 函數CORBA::ORB_init ()通過命令行參數初始化而得,客戶端與服務端都需要調用這個函數來初始化orb。orb在corba框架圖在的最下面,是它完成了具體的網絡連接的建立,以及請求/應答數據包在網絡在的傳輸。

poa對可移植的對象實配器,它是corba對象的管理者,corba 對象的創建,激活、生命期的管理,將客戶端的請求分發給servant 來實響應都是由poa來完成的。

3. 結束語

本節我們對corba中的概念作了介紹,特別地我們將概念與代碼作了對應。欲更具體地瞭解CORBA概念請參考《Advanced CORBA Programming with C++》的第二章第4節。

在示例在,客戶端需要訪問磁盤文件file://test.ior文件來初始化對象,並且此對象的引用是暫時的,每次重啓服務端後,test.ior文件就失效了。接下來,我們講一起學習POA,來開發更強大的服務端,敬請關注。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章