[openrtm-users 00460] Re: サービスポートのRTC以外からの利用に関して

Ando Noriaki n-ando @ aist.go.jp
2008年 6月 2日 (月) 18:57:37 JST


野村様

安藤です

いつもお世話になっております。

原因は、MyServiceA と MyServiceB で使用されているMyServiceSVC_implクラスの
名称(シンボル)が同じためだと思われます。

同一プロセス内に、同一名のシンボルがロードされた場合、
通常先にロードされたものが有効となります。
後からロードされたもの、(この場合は、MyServiceBのMyServiceSVC_impl)は
すでに同一名のクラスがあるため無効(無視される)となってしまいます。

したがって、MyServiceBでサービスポートに登録されたMyServiceSVC_implが
MyServcieAに付属しているMyServiceSVC_implクラスから生成された、
インスタンスをポートにバインドしてしまうものと思われます。

ためしに、CreateComp.cpp でロードする順番を以下のように変更してみました。

  strcpy(szDir,
"/usr/users/n-ando/work/TwoServices/sample/MyServiceB/MyServiceProviderB.so");
  manager->load(szDir, "MyServiceProviderBInit");

  strcpy(szDir,
"/usr/users/n-ando/work/TwoServices/sample/MyServiceA/MyServiceProviderA.so");
  manager->load(szDir, "MyServiceProviderAInit");

こうすると、

  Other properties
=================================================
echo MyServiceB[ function invokation succes ! MyServiceProviderB0]
echo MyServiceB[ function invokation succes ! MyServiceProviderA0]
echo MyServiceB[ function invokation succes ! MyServiceProviderB0]
echo MyServiceB[ function invokation succes ! MyServiceProviderA0]

このように、常にMyServiceBのサービスが呼ばれるようになります。

これを避ける方法としては、MyServiceA/BそれぞれのMyServiceSVC_implに
別々の名前をつけるか、それぞれ適当なnamespace (たとえば、MyServiceAやB)
に入れてしまうなどが考えられます。

余談ですが、0.4.2から、rtcdというマネージャのみの実行ファイルが追加(復活)されました。
これを使用すると、CreateCompの代わりに、
MyServiceProviderA.so, MyServiceProviderB.so を同一ディレクトリに置き、
そこに以下のような rtc.conf を作成したうえで、rtcd を起動すると、
これら二つのモジュールをロードして、同一プロセスに2つのコンポーネントを
生成することができます。

corba.nameservers: 192.168.100.1
naming.formats: %n
logger.log_level: PARANOID
manager.modules.load_path: ./
manager.modules.preload: MyServiceProviderA.so, MyServiceProviderB.so
manager.components.precreate: MyServiceProviderA, MyServiceProviderB

なお、この方法でももちろん上記の問題は解決されませんが、rtc.confの書き換えだけで、
ロード順番を試すことはできます。
なお、どちらのシンボルが採用されるかはロードされるときに決まりますので、
コンポーネント生成の順番には関係ありません。

以上で回答になってますでしょうか?
よろしくお願いいたします。

> 昔、下記添付メールのような投稿があったかと思いますが、これに関連して質問があります。
> 同じようなことを、複数のサービスポートに対して、さらに同一プロセス内で動作するローダブルコンポーネントで
> 実現しようとしています。
>
> (質問)
> 同一プロセス内で同じI/Fのサービスポートが複数ある場合には、
> それぞれ異なるサービスを実装することはできないのでしょうか?
>
> (構成)
> 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
>           [サービスA]
>              ↓
>
> [コンポーネントAのサービスプロバイダA]←─(同じI/F)←─┬─[アプリ](RTCではない)
> [コンポーネントBのサービスプロバイダB]←─(同じI/F)←─┘
>              ↑
>           [サービスB]
>
> (コンポーネントAとBを同一プロセス内で立ち上げる)
> 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
>
> (構成の説明)
> インターフェースは同じで、サービス内容の異なる2つのサービスプロバイダAとBを、
> それぞれ別々のコンポーネント上に構成し、同じプロセス内でコンポーネントAとBの両方を立ち上げます。
> そこへ、コンポーネントではないアプリからそれぞれのサービスポートを呼び出す、というものです。
>
> (現象)
> このとき、アプリからA/Bどちらのサービスポートを呼び出しても、サービスAの方が呼び出されてしまいました。
> 試しにコンポーネントA/Bをスタンドアローンとして立ち上げた場合(それぞれ別プロセスで立ち上げた場合)、
> 正しく呼び出すことができました。
> (サービスプロバイダAの呼び出しでサービスAが、サービスプロバイダBの呼び出しでサービスBが呼び出されました。)
>
> (サンプルコード)
> 上記の実験に使用したプログラムをサンプルプログラムとして添付します。
> すみませんが、CreateComp.cppの最初の方に絶対パスの記述がありますので、環境に合わせて書き換えてください。
>
> [フォルダ構成]
> sample/
> ├MyServiceA/   ・・・ 上図のサービスポートAを持つコンポーネントMyServiceAのフォルダ
> ├MyServiceB/   ・・・ 上図のサービスポートBを持つコンポーネントMyServiceBのフォルダ
> ├CreateComp   ・・・ MyServiceAとMyServiceBを立ち上げるプログラム
> └MyServiceCaller ・・・ 実行時のパラメータに"A"か"B"を入力することで、MyServiceAかMyServiceBを呼び出すアプリ
>
> [使い方]
> ・ネームサービスを立ち上げておき、CreateCompを実行してMyServiceAとMyServiceBを立ち上げる。
> ・"> ./MyServiceCaller A"と入力してMyServiceAを呼び出す
>   →"echo MyServiceA[〜〜〜"と表示され、MyServiceAのサービスが呼び出されていることが確認できる
> ・続いて、"> ./MyServiceCaller B"と入力してMyServiceBを呼び出す
>   →"echo MyServiceA[〜〜〜"と表示され、MyServiceAのサービスが呼び出されてしまっている
> ・試しに、CreateCompを使わずに、MyServiceACompとMyServiceBCompを使って立ち上げた場合には、
>   MyServiceBの呼び出しでMyServiceBのサービスが呼び出された。
>
>
> ちなみに試験した環境はUbuntu7.10、OpenRTM-0.4.1です。
> サービスポートの実装方法が間違っているのでしょうか?
>
> 長くて読みにくくなってしまい、申し訳ありませんが、
> お分かりになる方がいらしたらご教示下さい。
> どうぞ宜しくお願いします。
>
> ----------
> 野村 琢磨
> 株式会社 山武
> 生産技術開発部 自動化技術グループ
> E-mail:nomura-takuma @ jp.yamatake.com
> URL:http://jp.azbil.com
>
>
>
> ----- Original Message ----- From: "Ando Noriaki" <n-ando @ aist.go.jp>
> To: "Fumio Kanehiro" <f-kanehiro @ aist.go.jp>
> Cc: <openrtm-users @ m.aist.go.jp>
> Sent: Friday, November 16, 2007 9:17 AM
> Subject: [openrtm-users 00266] Re: サービスポートのRTC以外からの利用に関して
>
>
>> 金広様
>>
>> 安藤です
>>
>>> サービスポートに定義されているIDLのインタフェースをRTC以外の
>>> 通常のCORBAクライアントから呼び出す方法はありますでしょうか?
>>> どのようにするとサービスの参照を取得できるでしょうか?
>>
>> RTCのPortにconnectをする際に、そのポート自身のオブジェクトリファレンスのみ
>> をConnectorProfileにセットしてconnectしてください。
>> そうすると、戻ってきたConnectorProfile::propertiesの中に、
>> port.[Service Type].[Service Name] というキーでCORBA::Any型で
>> オブジェクトリファレンスが入っています。
>> それを、使用したいサービスの型にnarrowして使用してください。
>>
>> ちょっとごちゃごちゃしてますが、おおよそ以下のようになります。
>>
>> このファイルとMakefileを添付します。
>> 添付のtar-ballをexamples/SimpleServiceの下で展開しmakeしてください。
>> make -f Makefile.clientでmakeできます。
>>
>> このプログラムを試す手順は以下の通りです。
>> MyServiceProviderのサービスポートがProvideしてるMyServiceインターフェースを
>> 取得して、MyServiceインターフェースのオペレーションであるecho()を呼んでいます。
>>
>> 1. ネームサーバをローカルに立ち上げる
>> 2. MyServiceProviderをterminal1で立ち上げる
>> 3. terminal2で下のプログラムをコンパイルしたものを起動
>> 4. terminal1で以下のように表示される
>> MyService::echo() was called.
>> Message: hogehoge
>>
>> プログラム中にはクラスリファレンスおよびIDLリファレンスへのURLも
>> 書いてありますので適宜参照しながらごらんください。
>>
>>
>> ------------------
>> #include <rtm/CorbaNaming.h>
>> #include <iostream>
>> #include "MyService.hh"
>> #include <rtm/NVUtil.h>
>>
>> int main(int argc, char** argv)
>> {
>>  CORBA::ORB_var orb;
>>  orb = CORBA::ORB_init(argc, argv);
>>
>>  // RTC::CorbaNaming を使用してネームサーバにアクセス
>>  //
>> http://www.is.aist.go.jp/rt/OpenRTM-aist/doxygen/ClassReference/classRTC_1_1CorbaNaming.html
>>  RTC::CorbaNaming ns(orb, "localhost");
>>
>>  // RTObjectを取得
>>  //
>> http://www.is.aist.go.jp/rt/OpenRTM-aist/doxygen/IDLReference/interfaceRTC_1_1RTObject.html
>>  CORBA::Object_var obj = ns.resolve("MyServiceProvider0.rtc");
>>  RTC::RTObject_var rtc = RTC::RTObject::_narrow(obj);
>>
>>  // ComponentProfileを取得
>>  //
>> http://www.is.aist.go.jp/rt/OpenRTM-aist/doxygen/IDLReference/structRTC_1_1ComponentProfile.html
>>  RTC::ComponentProfile* prof;
>>  prof = rtc->get_component_profile();
>>  std::cout << "RTC name: " << prof->instance_name << std::endl;
>>
>>  // PortProfileを取得
>>  //
>> http://www.is.aist.go.jp/rt/OpenRTM-aist/doxygen/IDLReference/structRTC_1_1PortProfile.html
>>  RTC::PortProfileList port_prof;
>>  port_prof = prof->port_profiles;
>>  for (CORBA::ULong i(0), len(port_prof.length()); i < len; ++i)
>>   {
>>     std::cout << "name: " << port_prof[i].name << std::endl;
>>
>>     // インターフェースを表示してみる
>>     //
>> http://www.is.aist.go.jp/rt/OpenRTM-aist/doxygen/IDLReference/structRTC_1_1PortInterfaceProfile.html
>>     RTC::PortInterfaceProfileList  ifs(port_prof[i].interfaces);
>>     for (CORBA::ULong j(0), jlen(ifs.length()); j < jlen; ++j)
>> {
>>  std::cout << "IF name: " << ifs[j].instance_name << std::endl;
>>  std::cout << "IF type: " << ifs[j].type_name << std::endl;
>>  const char* pol;
>>  pol = ifs[j].polarity == RTC::PROVIDED ? "Provided" : "Required";
>>  std::cout << "IF polarity: " << pol << std::endl;
>> }
>>   }
>>
>>  RTC::Port_var port;
>>  port = port_prof[0].port_ref;
>>
>>
>>
>>  //
>>  // ConnectorProfile のportメンバに自分自身のリファレンスのみ入れて
>>  // connect する。戻ってきたConnectorProfileのpropertiesの中には
>>  // サービスのObjectReferenceが入っているので取得する。
>>  //
>>  // サービスの接続に関する情報はクラスリファレンスのCorbaPortを参照
>>  //
>> http://www.is.aist.go.jp/rt/OpenRTM-aist/doxygen/ClassReference/classRTC_1_1CorbaPort.html
>>  //
>>  // ConnectorProfile
>>  //
>> http://www.is.aist.go.jp/rt/OpenRTM-aist/doxygen/IDLReference/structRTC_1_1ConnectorProfile.html
>>  RTC::ConnectorProfile con_prof;
>>  con_prof.name = CORBA::string_dup("tekitouna_namae0");
>>  con_prof.connector_id = "";
>>  con_prof.ports.length(1);
>>  con_prof.ports[0] = port;
>>  con_prof.properties.length(0);
>>  if (CORBA::is_nil(port))
>>   {
>>     std::cout << "nil reference" << std::endl;
>>     return 0;
>>   }
>>
>>  if (port->connect(con_prof) != RTC::RTC_ERROR)
>>   {
>>     // エラーは無視
>>     std::cout << "ignore error" << std::endl;
>>   }
>>  std::cout << "connect OK" << std::endl;
>>
>>  CORBA::Object_ptr aobj;
>>  MyService_var mysvc;
>>
>>  // NVUtilでpropertiesの中からサービスのオブジェクトリファレンスを取得
>>  //
>> http://www.is.aist.go.jp/rt/OpenRTM-aist/doxygen/ClassReference/namespaceNVUtil.html
>>  if (NVUtil::find(con_prof.properties, "port.MyService.myservice0")
>>>>
>>>> = CORBA::Any::to_object(aobj))
>>
>>   {
>>     mysvc = MyService::_narrow(aobj);
>>   }
>>
>>  // サービスを呼ぶ
>>  mysvc->echo("hogehoge");
>>  // MyServiceProviderを実行した画面で以下のように表示されるはず
>>  //
>>  // MyService::echo() was called.
>>  // Message: hogehoge
>>
>>
>>
>> }
>>
>>
>>
>> --
>> 安藤慶昭@独立行政法人産業技術総合研究所 研究員
>>                  知能システム研究部門 タスクインテリジェンス研究グループ
>>                  〒305-8568 茨城県つくば市梅園1-1-1 中央第2
>>                  TEL: 029-861-5981 FAX: 029-861-5971
>>                  n-ando @ aist.go.jp, n-ando @ ieee.org
>>
>



-- 
安藤慶昭@独立行政法人産業技術総合研究所 研究員
 知能システム研究部門 タスクインテリジェンス研究グループ
 〒305-8568 茨城県つくば市梅園1-1-1 中央第2
 TEL: 029-861-5981 FAX: 029-861-5971
 n-ando @ aist.go.jp, n-ando @ ieee.org



openrtm-users メーリングリストの案内