動機
昨日からCORBAのテストアプリケーションを動かしているが,localhostではうまくいくのに,サーバ/クライアントを別マシンにするとエラーが出て落ちる..
調査
下記のエラーが出て落ちる
uncaught MICO exception: IDL:omg.org/CORBA/COMM_FAILURE:1.0 (0, not-completed)
原因を見つけるために `netstat -c` で監視しつつ,例外メッセージを調べていたらなんとなく原因が分かってきた.どうもCORBAではリスナーポートにアクセスしてきた元のポートにそのままデータを返すみたい.これはJavaだけど,このような例外らしい.
netstat -cで確認をしたところ
Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 hoge:44532 hoge:5005 ESTABLISHED tcp 0 0 hoge:5005 hoge:44532 ESTABLISHED tcp 0 0 hoge:5005 fuga:3901 ESTABLISHED
この直後に3番目の通信が切れ,test_client.shが上記の例外を吐いて落ちる.おそらくclientがNameServerにたどり着いた後,NameServerがfugaの3901番ポートにアクセスしようとして,ポートの接続制限によって通信が切断されるためではないかと思われる.
ためしにNameServer, test_server, test_clientをすべてhoge上で行ったときは,
Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 localhost.localdo:42688 localhost.localdo:60095 ESTABLISHED tcp 0 0 hoge:44724 hoge:5005 ESTABLISHED tcp 0 0 localhost.localdo:60095 localhost.localdo:42688 ESTABLISHED tcp 0 0 hoge:44725 hoge:5005 ESTABLISHED tcp 0 0 hoge:5005 hoge:44725 ESTABLISHED tcp 0 0 hoge:5005 hoge:44724 ESTABLISHED
hoge上の44724番ポートから5005番にアクセスしているのがserverで,44725番から5005番にアクセスしているのがclient.NameServerは5005番からserverとclient,両方のポートにアクセスできています.またlocalhost.localdo:42688と60095が何をしているのかがよくわからないけど,とりあえずポート周りであろうと分かった.
テストコード
test_server.idl
interface TestServer { long display_message(in string msg); long get_message(out string msg); void destroy(); }; interface TestServerFactory { TestServer create(); };
test_server_impl.h
class TestServer_impl : virtual public POA_TestServer { public: TestServer_impl(); ~TestServer_impl(); CORBA::Long display_message(const char* msg); CORBA::Long get_message(CORBA::String_out msg); void destroy(); }; class TestServerFactory_impl : virtual public POA_TestServerFactory { public: TestServerFactory_impl(); ~TestServerFactory_impl(); TestServer_ptr create(); };
test_server_impl.cc
#include "test_server_impl.h" #include <iostream> using namespace std; TestServer_impl::TestServer_impl() { } TestServer_impl::~TestServer_impl() { } CORBA::Long TestServer_impl::display_message(const char* msg) { cerr << msg << endl; return 0; } CORBA::Long TestServer_impl::get_message(CORBA::String_out msg) { msg = CORBA::string_dup("I am TestServer"); return 0; } void TestServer_impl::destroy() { PortableServer::POA_var poa = _default_POA(); PortableServer::ObjectId_var id = poa->servant_to_id(this); poa->deactivate_object(id); } TestServer_ptr TestServerFactory_impl::create() { TestServer_impl* test = new TestServer_impl; TestServer_ptr tref = test->_this(); if(CORBA::is_nil(tref)) { cerr << "TestServerFactory: failed to create TestServer object" << endl; } return tref; } TestServerFactory_impl::TestServerFactory_impl() { } TestServerFactory_impl::~TestServerFactory_impl() { PortableServer::POA_var poa = _default_POA(); PortableServer::ObjectId_var id = poa->servant_to_id(this); poa->deactivate_object(id); }
test_client.cc
#include <coss/CosNaming.h> #include <test_server.h> #include <iostream> using namespace std; int main(int argc, char** argv) { CORBA::ORB_var orb = CORBA::ORB_init (argc, argv); /* * Acquire a reference to the Naming Service */ CORBA::Object_var nsobj; CosNaming::NamingContext_var nc; try { nsobj = orb->resolve_initial_references ("NameService"); nc = CosNaming::NamingContext::_narrow (nsobj); } catch(CORBA::Exception& ex) { cerr << "client: error at connecting to NameService" << endl; return 1; } if (CORBA::is_nil (nc)) { cerr << "client: I cannot access the Naming Service!" << endl; return 1; } CosNaming::Name name; name.length (1); name[0].id = CORBA::string_dup ("TestServer"); name[0].kind = CORBA::string_dup (""); /* * try to find that node in the Naming Service tree */ CORBA::Object_var obj; try { obj = nc->resolve(name); } catch(CORBA::Exception& ex) { cerr << "client: cannot connect to TestServerFactory" << endl; return 1; } cerr << "client: connected to TestServerFactory" << endl; /* * The Naming Service returns a generic reference as a CORBA::Object * We need to narrow this to the desired type */ cerr << "creating TestServerFactory object" << endl; TestServerFactory_var fact = TestServerFactory::_narrow (obj); TestServer_var test = fact->create(); if (CORBA::is_nil(test)) { cerr << "client: cannot create TestServer" << endl; return 1; } test->display_message("Hello!"); CORBA::String_var msg; test->get_message(msg); cout << (const char*)msg << endl; test->destroy(); return 0; }
起動時の各オプション
# nsd -ORBIIOPAddr inet:hoge:5005 # ./server.exe -ORBInitRef NameService=corbaloc::hoge:5005/NameServer # ./client.exe -ORBInitRef NameService=corbaloc::hoge:5005/NameServer
テスト動作(成功時)
- server側
# ./server.exe -ORBInitRef NameService=corbaloc::hoge:5005/NameServer TestServer: binding in the Naming Service ... done. TestServer: ready Hello!
- client側
# ./client.exe -ORBInitRef NameService=corbaloc::hoge:5005/NameServer client: connected to TestServerFactory I am TestServer
テスト動作(エラー時)
- client側
# ./client.exe -ORBInitRef NameService=corbaloc::hoge:5005/NameServer client: connected to TestServerFactory creating TestServerFactory object uncaught MICO exception: IDL:omg.org/CORBA/COMM_FAILURE:1.0 (0, not-completed)
まとめ
クライアントの使用ポートを指定する方法はないのかなぁ?それができればポートの開放とかも楽になるんだけど.是非ご教授願いたい.