我们先用c++实现服务端和客户端,然后再用java编写客户端。
1. 首先安装omniORB,omniORB提供 omniidl命令,以及一些头文件和库。
omniORB一般是需要你自己进行编译。
2. 编写idl文件,本实验中文件名为 echo.idl
1 interface Echo { string echoString(in string mesg); };
echo.idl
3. 使用omniidl -bcxx echo.idl 生成 echo.hh 和 echoSK.cc
4. 编写用c++实现的服务端和客户端,本实验中是 server.cpp client.cpp
1 // eg3_impl.cc - This is the source code of example 3 used in Chapter 2 2 // "The Basics" of the omniORB user guide. 3 // 4 // This is the object implementation. 5 // 6 // Usage: eg3_impl 7 // 8 // On startup, the object reference is registered with the 9 // COS naming service. The client uses the naming service to 10 // locate this object. 11 // 12 // The name which the object is bound to is as follows: 13 // root [context] 14 // | 15 // test [context] kind [my_context] 16 // | 17 // Echo [object] kind [Object] 18 // 19 20 #include "echo.hh" 21 22 #ifdef HAVE_STD 23 # include <iostream> 24 using namespace std; 25 #else 26 # include <iostream.h> 27 #endif 28 29 static CORBA::Boolean bindObjectToName(CORBA::ORB_ptr, CORBA::Object_ptr); 30 31 32 class Echo_i : public POA_Echo 33 { 34 public: 35 inline Echo_i() {} 36 virtual ~Echo_i() {} 37 virtual char* echoString(const char* mesg); 38 }; 39 40 41 char* Echo_i::echoString(const char* mesg) 42 { 43 return CORBA::string_dup(mesg); 44 } 45 46 ////////////////////////////////////////////////////////////////////// 47 48 int 49 main(int argc, char **argv) 50 { 51 try { 52 CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); 53 CORBA::Object_var obj = orb->resolve_initial_references("RootPOA"); 54 PortableServer::POA_var poa = PortableServer::POA::_narrow(obj); 55 56 PortableServer::Servant_var<Echo_i> myecho = new Echo_i(); 57 58 PortableServer::ObjectId_var myechoid = poa->activate_object(myecho); 59 60 // Obtain a reference to the object, and register it in 61 // the naming service. 62 obj = myecho->_this(); 63 64 CORBA::String_var sior(orb->object_to_string(obj)); 65 cout << sior << endl; 66 67 if (!bindObjectToName(orb, obj)) 68 return 1; 69 70 PortableServer::POAManager_var pman = poa->the_POAManager(); 71 pman->activate(); 72 73 orb->run(); 74 } 75 catch (CORBA::SystemException& ex) { 76 cerr << "Caught CORBA::" << ex._name() << endl; 77 } 78 catch (CORBA::Exception& ex) { 79 cerr << "Caught CORBA::Exception: " << ex._name() << endl; 80 } 81 return 0; 82 } 83 84 ////////////////////////////////////////////////////////////////////// 85 86 static CORBA::Boolean 87 bindObjectToName(CORBA::ORB_ptr orb, CORBA::Object_ptr objref) 88 { 89 CosNaming::NamingContext_var rootContext; 90 91 try { 92 // Obtain a reference to the root context of the Name service: 93 CORBA::Object_var obj = orb->resolve_initial_references("NameService"); 94 95 // Narrow the reference returned. 96 rootContext = CosNaming::NamingContext::_narrow(obj); 97 if (CORBA::is_nil(rootContext)) { 98 cerr << "Failed to narrow the root naming context." << endl; 99 return 0; 100 } 101 } 102 catch (CORBA::NO_RESOURCES&) { 103 cerr << "Caught NO_RESOURCES exception. You must configure omniORB " 104 << "with the location" << endl 105 << "of the naming service." << endl; 106 return 0; 107 } 108 catch (CORBA::ORB::InvalidName&) { 109 // This should not happen! 110 cerr << "Service required is invalid [does not exist]." << endl; 111 return 0; 112 } 113 114 try { 115 // Bind a context called "test" to the root context: 116 117 CosNaming::Name contextName; 118 contextName.length(1); 119 contextName[0].id = (const char*) "test"; // string copied 120 contextName[0].kind = (const char*) "my_context"; // string copied 121 // Note on kind: The kind field is used to indicate the type 122 // of the object. This is to avoid conventions such as that used 123 // by files (name.type -- e.g. test.ps = postscript etc.) 124 125 CosNaming::NamingContext_var testContext; 126 try { 127 // Bind the context to root. 128 testContext = rootContext->bind_new_context(contextName); 129 } 130 catch(CosNaming::NamingContext::AlreadyBound& ex) { 131 // If the context already exists, this exception will be raised. 132 // In this case, just resolve the name and assign testContext 133 // to the object returned: 134 CORBA::Object_var obj = rootContext->resolve(contextName); 135 testContext = CosNaming::NamingContext::_narrow(obj); 136 if (CORBA::is_nil(testContext)) { 137 cerr << "Failed to narrow naming context." << endl; 138 return 0; 139 } 140 } 141 142 // Bind objref with name Echo to the testContext: 143 CosNaming::Name objectName; 144 objectName.length(1); 145 objectName[0].id = (const char*) "Echo"; // string copied 146 objectName[0].kind = (const char*) "Object"; // string copied 147 148 try { 149 testContext->bind(objectName, objref); 150 } 151 catch(CosNaming::NamingContext::AlreadyBound& ex) { 152 testContext->rebind(objectName, objref); 153 } 154 // Note: Using rebind() will overwrite any Object previously bound 155 // to /test/Echo with obj. 156 // Alternatively, bind() can be used, which will raise a 157 // CosNaming::NamingContext::AlreadyBound exception if the name 158 // supplied is already bound to an object. 159 } 160 catch (CORBA::TRANSIENT& ex) { 161 cerr << "Caught system exception TRANSIENT -- unable to contact the " 162 << "naming service." << endl 163 << "Make sure the naming server is running and that omniORB is " 164 << "configured correctly." << endl; 165 166 return 0; 167 } 168 catch (CORBA::SystemException& ex) { 169 cerr << "Caught a CORBA::" << ex._name() 170 << " while using the naming service." << endl; 171 return 0; 172 } 173 return 1; 174 }
server.cpp
1 // eg3_clt.cc - This is the source code of example 3 used in Chapter 2 2 // "The Basics" of the omniORB user guide. 3 // 4 // This is the client. It uses the COSS naming service 5 // to obtain the object reference. 6 // 7 // Usage: eg3_clt 8 // 9 // 10 // On startup, the client lookup the object reference from the 11 // COS naming service. 12 // 13 // The name which the object is bound to is as follows: 14 // root [context] 15 // | 16 // text [context] kind [my_context] 17 // | 18 // Echo [object] kind [Object] 19 // 20 21 #include "echo.hh" 22 23 #ifdef HAVE_STD 24 # include <iostream> 25 using namespace std; 26 #else 27 # include <iostream.h> 28 #endif 29 30 static CORBA::Object_ptr getObjectReference(CORBA::ORB_ptr orb); 31 32 static void hello(Echo_ptr e) 33 { 34 if (CORBA::is_nil(e)) { 35 cerr << "hello: The object reference is nil!\n" << endl; 36 return; 37 } 38 39 CORBA::String_var src = (const char*) "Hello!"; 40 41 CORBA::String_var dest = e->echoString(src); 42 43 cerr << "I said, \"" << (char*)src << "\"." << endl 44 << "The Echo object replied, \"" << (char*)dest <<"\"." << endl; 45 } 46 47 ////////////////////////////////////////////////////////////////////// 48 49 int 50 main (int argc, char **argv) 51 { 52 try { 53 CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); 54 55 CORBA::Object_var obj = getObjectReference(orb); 56 57 Echo_var echoref = Echo::_narrow(obj); 58 59 for (CORBA::ULong count=0; count < 10; count++) 60 hello(echoref); 61 62 orb->destroy(); 63 } 64 catch (CORBA::TRANSIENT&) { 65 cerr << "Caught system exception TRANSIENT -- unable to contact the " 66 << "server." << endl; 67 } 68 catch (CORBA::SystemException& ex) { 69 cerr << "Caught a CORBA::" << ex._name() << endl; 70 } 71 catch (CORBA::Exception& ex) { 72 cerr << "Caught CORBA::Exception: " << ex._name() << endl; 73 } 74 return 0; 75 } 76 77 ////////////////////////////////////////////////////////////////////// 78 79 static CORBA::Object_ptr 80 getObjectReference(CORBA::ORB_ptr orb) 81 { 82 CosNaming::NamingContext_var rootContext; 83 84 try { 85 // Obtain a reference to the root context of the Name service: 86 CORBA::Object_var obj; 87 obj = orb->resolve_initial_references("NameService"); 88 89 // Narrow the reference returned. 90 rootContext = CosNaming::NamingContext::_narrow(obj); 91 92 if (CORBA::is_nil(rootContext)) { 93 cerr << "Failed to narrow the root naming context." << endl; 94 return CORBA::Object::_nil(); 95 } 96 } 97 catch (CORBA::NO_RESOURCES&) { 98 cerr << "Caught NO_RESOURCES exception. You must configure omniORB " 99 << "with the location" << endl 100 << "of the naming service." << endl; 101 return CORBA::Object::_nil(); 102 } 103 catch (CORBA::ORB::InvalidName& ex) { 104 // This should not happen! 105 cerr << "Service required is invalid [does not exist]." << endl; 106 return CORBA::Object::_nil(); 107 } 108 109 // Create a name object, containing the name test/context: 110 CosNaming::Name name; 111 name.length(2); 112 113 name[0].id = (const char*) "test"; // string copied 114 name[0].kind = (const char*) "my_context"; // string copied 115 name[1].id = (const char*) "Echo"; 116 name[1].kind = (const char*) "Object"; 117 // Note on kind: The kind field is used to indicate the type 118 // of the object. This is to avoid conventions such as that used 119 // by files (name.type -- e.g. test.ps = postscript etc.) 120 121 try { 122 // Resolve the name to an object reference. 123 return rootContext->resolve(name); 124 } 125 catch (CosNaming::NamingContext::NotFound& ex) { 126 // This exception is thrown if any of the components of the 127 // path [contexts or the object] aren‘t found: 128 cerr << "Context not found." << endl; 129 } 130 catch (CORBA::TRANSIENT& ex) { 131 cerr << "Caught system exception TRANSIENT -- unable to contact the " 132 << "naming service." << endl 133 << "Make sure the naming server is running and that omniORB is " 134 << "configured correctly." << endl; 135 } 136 catch (CORBA::SystemException& ex) { 137 cerr << "Caught a CORBA::" << ex._name() 138 << " while using the naming service." << endl; 139 } 140 return CORBA::Object::_nil(); 141 }
client.cpp
5. 编写makefile,用于生成c++的客户端和服务端
1 CXX=g++ 2 FLAGS=-Wall 3 4 all:server client 5 6 server:server.cpp echoSK.cc echo.hh 7 $(CXX) $(FLAGS) -o [email protected] server.cpp echoSK.cc -lomnithread -lomniORB4 8 9 client:client.cpp echoSK.cc echo.hh 10 $(CXX) $(FLAGS) -o [email protected] client.cpp echoSK.cc -lomnithread -lomniORB4 11 12 clean: 13 rm server client 14 15
makefile
6. 执行make命令,生成 server 和client 的二进制文件
7. 启动 tnameserv
sudo tnameserv
该命令会同时告诉我们端口号,这里是900
8. 启动服务端
./server -ORBInitRef NameService=corbaloc::localhost:900/NameService
9. 启动客户端
./client -ORBInitRef NameService=corbaloc::localhost:900/NameService
10. 现在为止,我们已经用 c++ 实现了服务端和客户端,接下来我们用java实现客户端,服务端依然使用之前 make 生成的。
11. 现在用idlj 生成一些必要的 java 文件
idlj echo.idl
12. 编写java客户端,本实验中是 javaclient.java
1 //import HelloApp.*; 2 import org.omg.CosNaming.*; 3 import org.omg.CosNaming.NamingContextPackage.*; 4 import org.omg.CORBA.*; 5 6 public class javaclient 7 { 8 static Echo echoImpl; 9 10 public static void main(String args[]) 11 { 12 try{ 13 // create and initialize the ORB 14 ORB orb = ORB.init(args, null); 15 16 // get the root naming context 17 org.omg.CORBA.Object objRef = 18 orb.resolve_initial_references("NameService"); 19 // Use NamingContextExt instead of NamingContext. This is 20 // part of the Interoperable naming Service. 21 NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef); 22 23 // resolve the Object Reference in Naming 24 //String name = "Hello"; 25 NameComponent name0=new NameComponent("test","my_context"); 26 NameComponent name1=new NameComponent("Echo","Object"); 27 echoImpl = EchoHelper.narrow(ncRef.resolve(new NameComponent[]{name0,name1})); 28 29 System.out.println("Obtained a handle on server object: " + echoImpl); 30 System.out.println(echoImpl.echoString("Hello")); 31 //echoImpl.shutdown(); 32 33 } catch (Exception e) { 34 System.out.println("ERROR : " + e) ; 35 e.printStackTrace(System.out); 36 } 37 } 38 39 }
javaclient.java
13. 编译java 客户端
javac *.java
14. 执行java客户端
java javaclient -ORBInitRef NameService=corbaloc::localhost:900/NameService
15. 附带给出一个脚本,用于删除那些由程序生成的文件,可以用来清理项目
1 #!/bin/bash 2 3 rm client 4 rm server 5 rm *.class 6 rm echo.hh 7 rm echoSK.cc 8 rm _EchoStub.java 9 rm EchoHelper.java 10 rm EchoHolder.java 11 rm EchoOperations.java
rmunneededfile.sh
16. 结束
Trouble shooting:
1. 编译出来c++的server,在运行时出现没有找到.so的问题,于是使用ldd命令找到运行server时缺少的库,实际的.so所在的目录是/usr/local/lib,尝试将该目录添加到PATH环境变量中,发现没有效果(大概寻找.so时搜索的路径不是PATH环境变量),于是在/usr/lib下建了所缺少的.so的符号链接,问题解决。
2. 在ubuntu中,编译omniORB会出现无法找到python头文件的问题,原因是python的头文件存在于单独的包中,名为 libpython2.7-dev。