180 likes | 365 Views
第三章 一个最小的 CORBA 应用程序. 3.1 本章概述 本章介绍如何建立一个简单的 CORBA 应用程序,它由一个简单的服务器程序和一个能访问这个对象的客户机组成,在此将熟悉创建一个最小的应用程序都需要有那些基本不骤,另外还有一些程序员代码的解释细节。 3.2 编写和编译一个 IDL 定义。 CORBA 应用程序第一步是用 IDL 定义它的接口,下面的 IDL 中包含了一个结构定义和一个单独的接口。 struct TimeOfDay { short hour; // 0 - 23
E N D
第三章 一个最小的CORBA应用程序 • 3.1 本章概述 本章介绍如何建立一个简单的CORBA应用程序,它由一个简单的服务器程序和一个能访问这个对象的客户机组成,在此将熟悉创建一个最小的应用程序都需要有那些基本不骤,另外还有一些程序员代码的解释细节。 3.2 编写和编译一个IDL定义。 CORBA应用程序第一步是用IDL定义它的接口,下面的IDL中包含了一个结构定义和一个单独的接口。 struct TimeOfDay { short hour; // 0 - 23 short minute; // 0 - 59 short second; // 0 - 59 }; interface Time { TimeOfDay get_gmt(); };
第三章 一个最小的CORBA应用程序 • 接口Time定义一个传送当前时间的对象,Time对象只有一个单个的操作get_gmt。客户调用这个操作来获得当前时间。当前时间是以结构类型TimeofDay形式表示当前时间。 • 文件存成time.idl,并对其进行编译。然而不同供应商提供的ORB不同,则可能生成的文件就不同,可是基础概念对所有使用C++语言映射的对象都是一样。 • $ idl time.idl • 将生成若干新的文件。 • time.hh 这是插入在客户机程序的源代码中的头文件。它包含time.idl中用到的类型在C++类型定义。 • timeC.cc 此文件包含编译和连接客户应用程序的C++存根代码。它提供一个生成的API,客户机应用程序可以调用这个API来与在time.idl所定义的对象进行通信。
第三章 一个最小的CORBA应用程序 • timeS.hh 这是一个插入在服务器程序源代码中的头文件。它包含一些定义这些定义允许应用程序代码实现一个在time.idl中定义的对象。 • timeS.cc 这个文件包含编译和连接入服务器应用程序的C++框架。它提供这个服务器应用程序所需的运行时支持,所以它能够接收客户机程序发送的操作调用。 • 3.3 编写和编译一个服务器程序 整个服务器程序的源代码如下: #include <time.h> #include <iostream.h> #include "server.hh“ class Time_impl : public virtual POA_Time { public: virtual TimeOfDay get_gmt() throw(CORBA::SystemException); };
第三章 一个最小的CORBA应用程序 • TimeOfDay • Time_impl:: • get_gmt() throw(CORBA::SystemException) • { • time_t time_now = time(0); • struct tm * time_p = gmtime(&time_now); • TimeOfDay tod; • tod.hour = time_p->tm_hour; • tod.minute = time_p->tm_min; • tod.second = time_p->tm_sec; • return tod; • }
第三章 一个最小的CORBA应用程序 • int • main(int argc, char * argv[]) • { • try { • // Initialize orb • CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); • // Get reference to Root POA. • CORBA::Object_var obj • = orb->resolve_initial_references("RootPOA"); • PortableServer::POA_var poa • = PortableServer::POA::_narrow(obj); • // Activate POA manager • PortableServer::POAManager_var mgr • = poa->the_POAManager(); • mgr->activate();
第三章 一个最小的CORBA应用程序 • // Create an object • Time_impl time_servant; • // Write its stringified reference to stdout • Time_var tm = time_servant._this(); • CORBA::String_var str = orb->object_to_string(tm); • cout << str << endl; • // Accept requests • orb->run(); • } • catch (const CORBA::Exception &) { • cerr << "Uncaught CORBA exception" << endl; • return 1; • } • return 0; • }
第三章 一个最小的CORBA应用程序 • 此服务器实现了一个Time对象,头文件timeS.hh包含一个称为POA_Time的抽象定义。定义如下: • // In file timeS.hh • class POA_Time: • public virtual PortableServer::ServerBase{ • public: • virtual ~POA_Time(); • Time_ptr _this(); • virtual TimeofDay get_gmt() • throw(CORBA::SystemException)=0; • }; • 这个类包含一个get_gmt纯虚拟方法。为了创建一个客户机程序可以调用的实现对象,在此必须为get_gmt方法提供一个实现的POA_Time中派生一个具体类。这就是说头几行编码应该如下: #include <time.h> #include <iostream.h> #include "server.hh“ class Time_impl : public virtual POA_Time { public: virtual TimeOfDay get_gmt() throw(CORBA::SystemException);};
第三章 一个最小的CORBA应用程序 • 在此定义了从POA_Time派生来的类Time_impl。这个类提供了一个客户机真正能够与其通信的Time对象的一个具体实现。 • 下一步是Time_impl中get_gmt方法的实现。忽略出错,返回值为-1,则返回一个毫无意义的时间值,而不引发异常。 • TimeOfDay • Time_impl:: • get_gmt() throw(CORBA::SystemException) • { • time_t time_now = time(0); • struct tm * time_p = gmtime(&time_now); • TimeOfDay tod; • tod.hour = time_p->tm_hour; • tod.minute = time_p->tm_min; • tod.second = time_p->tm_sec; • return tod; • }
第三章 一个最小的CORBA应用程序 主函数 • 以上程序完成了对象的实现,下面是main函数。头几行代码对于多数服务器都一样,是对服务器端ORB的初始化。 • 下步是提供一个Time对象的实际司服程序,以便客户机发送一个调用给它。可以通过创建一个Time_impl司服类得是例来完成。 • Time_impl time_servant; //create a Time Object • 为了客户机能够访问这个对象,客户机需要一个对象引用,在此通过将它作为字符串写到stdout中来提供这个引用。 • // Write its stringified reference to stdout • Time_var tm = time_servant._this(); • CORBA::String_var str = orb->object_to_string(tm); • cout << str << endl;
第三章 一个最小的CORBA应用程序 • 对_this的调用创建了这个对象的对象引用。 • 有了一个Time对象的具体实现,客户程序就可以引用它,现在,服务器就可以接受请求了,在运行时,通过调用run来指示ORB做些什么。 • orb->run(); //接收请求 • Run方法开始进入时间循环,等待有客户机程序发出的请求。 • 剩下的代码为一个异常处理程序,它输出一个错误消息并终止main。 • } • catch (const CORBA::Exception &) { • cerr << "Uncaught CORBA exception" << endl; • return 1; • } • return 0; • } • 完成以上任务后,就可编译和连接服务器程序代码。 • $ CC –c –I/opt/myORB/include timeC.cc • $ CC –c –I/opt/myORB/include times.cc • $ CC –c –I/opt/myORB/include myserver.cc
第三章 一个最小的CORBA应用程序 • 如果没有错误,将产生三个可以连接成一个可执行程序的对象文件。 • $ CC –O myserver timeC.o timeS.o myserver.o\ • >-L/opt/myORB/lib –lorb • 假设ORB运行库为liborb。这样就可运行此程序。运行后,服务器程序在stdout上输出一个引用给它的Time对象,然后,一直等待客户请求。客户机发信号给它,它才终止。 • 3.4 编写和编译一个客户程序 • 客户机的源代码如下: #include <iostream.h> #include <iomanip.h> #include "time.hh" //----------------------------------------------------------------------------- int main(int argc, char * argv[]) {
第三章 一个最小的CORBA应用程序 try { // Check arguments if (argc != 2) { cerr << "Usage: client IOR_string" << endl; throw 0; } // Initialize orb CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); // Destringify argv[1] CORBA::Object_var obj = orb->string_to_object(argv[1]); if (CORBA::is_nil(obj)) { cerr << "Nil Time reference" << endl; throw 0; } // Narrow Time_var tm = Time::_narrow(obj); if (CORBA::is_nil(tm)) { cerr << "Argument is not a Time reference" << endl; throw 0; }
第三章 一个最小的CORBA应用程序 // Get time TimeOfDay tod = tm->get_gmt(); cout << "Time in Greenwich is " << setw(2) << setfill('0') << tod.hour << ":" << setw(2) << setfill('0') << tod.minute << ":" << setw(2) << setfill('0') << tod.second << endl; } catch (const CORBA::Exception &) { cerr << "Uncaught CORBA exception" << endl; return 1; } catch (...) { return 1; } return 0; }
第三章 一个最小的CORBA应用程序 • 必须包含一个客户端的头文件time.hh,以便IDL定义能用于客户机应用程序代码,先做了个参数检验,并用ORB_init来初始化ORB的运行状态。 #include <iostream.h> #include <iomanip.h> #include "time.hh“ int main(int argc, char * argv[]) { try { // Check arguments if (argc != 2) { cerr << "Usage: client IOR_string" << endl; throw 0; } // Initialize orb CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
第三章 一个最小的CORBA应用程序 • 发送了一个零来实现一个简单的出错处理形式,在main函数的结尾处的异常处理程序保证了如果出现任何问题错误,客户机将以非零状态退出。 • 接下来几行代码将命令参数(一个对对象Time的字符串化引用)转换成一个对象引用: // Destringify argv[1] CORBA::Object_var obj = orb->string_to_object(argv[1]); if (CORBA::is_nil(obj)) { cerr << "Nil Time reference" << endl; throw 0; } 这样就形成了一个object类型的对象引用。但客户程序根据这个引用能够调用一个操作之前,它必须将引用强制转换为正确的类型,即Time。 // Narrow Time_var tm = Time::_narrow(obj); if (CORBA::is_nil(tm)) { cerr << "Argument is not a Time reference" << endl; throw 0; }
第三章 一个最小的CORBA应用程序 • 对Time_narrow的调用起着一个强制动态类型的转换(dynamic cast)相同的目的,它测试一个引用是否是指定类型。如果是,_narrow返回一个非零引用,否则位零引用。 • 现在,这个对象程序已拥有在服务器上被激活的Time对象的对象引用,用这个对象引用可以获得当前时间值: // Get time TimeOfDay tod = tm->get_gmt(); cout << "Time in Greenwich is " << setw(2) << setfill('0') << tod.hour << ":" << setw(2) << setfill('0') << tod.minute << ":" << setw(2) << setfill('0') << tod.second << endl; 对get_gmt的调用将激活在服务器中对get_gmt方法远程过程调用,这个调用一直到服务器返回当前时间值是才阻塞,客户程序在stuout输出这个结果。 整个过程与服务器位于什么位置毫无关系。ORB将负责Time对象的定位,并调用这个请求给对象,整个过程是透明的。 客户程序的命令部分是由两个异常处理组成,处理出错。
第三章 一个最小的CORBA应用程序 • 以上步骤完成后,便可对其进行编译和连接: $ CC –c –I/opt/myORB/include timeC.cc $ CC –c –I/opt/myORB/include myclient.cc $ CC –O myclient timeC.o myclient.o\ >-L/opt/myORB/lib –lorb 假如没错误,将产生一个myclient客户即可执行的程序 • 3.5 运行客户机和服务器程序 先运行服务器,应将服务器程序输出的对象引用字符串重定向到一个文件中,以便将它传递给客户机程序的命令行。为了在服务器程序运行时,继续使用终端,将服务器程序放在后台执行。 在服务器程序运行后,启动客户程序,将由服务器在命令行输出的那个对象引用传递给它,客户程序根据传给的引用读入当前时间值,并且在它推出前将时间值输出到stdout。最后,通过发送一个SIGTERM给它来终止这个服务器程序。
第三章 一个最小的CORBA应用程序 • $ ./myserver>tmp/myserver.ref & • [1] 7898 • $ ./myclient ‘cat/tmp/myserver.ref’ • Time in Greenwich is 23:47:56 • $ kill %1 • [1] + Terminated ./myserver & • $ • 建立一个完整的应用程序需要涉及四个步骤: • 1. 定义IDL • 2. 编译IDL • 3. 编写和编译服务器程序 • 3. 编写和编译客户程序 • 如果服务器程序是现成的,你只要编写一个与服务器程序通信的客户程序就可以了。因此第1步和第三步就不用了。