CORBA组件编程方法实例+分析

    xiaoxiao2022-12-06  50

    预警:本篇中有大量截图+代码/代码段

    关于CORBA组件的应用老师上课时给我们讲了个例子:没登录qq时不能用qq截图,只有登录上了qq才能用。也就是启动了qq服务端之后才能在客户端使用服务端上的服务。本篇中的两个实例也是出于类似的应用。


    一、配置环境

           我参考的是这篇文章https://www.jianshu.com/p/1fbc600de9cf,如果不在ecplise运行配置到第三步就可以了。

           我在配置的时候遇到了坑,那就是按上面教程配置好后出现了报错org.omg.CORBA不存在。这里要求java的jdk版本一定不能太高了(我也不知道为嘛),笔记本上面jdk是10以上的就不行,要改成低版本的!这里提供一个低版本的jdk:https://pan.baidu.com/s/1rAz3H-DfSOvaVpxuQGoU0w 提取码:cukz 

          我在改的时候还犯错了:直接在path里面加上了低版本的路径,这样也是不行的,在编译Server和Client时我遇到的报错是:

    建议重新多建一个JAVA_HOME,具体过程可以百度“java多个版本jdk环境变量配置”。

    二、实例

    ps:我的代码都是写在记事本里面的,没有用eclipse

    【实例一:Java版CORBA程序1——HelloWorld】

    它的作用是输出一个字符串"HelloWorld+班级+姓名"

    1.编写IDL接口HelloWorld.idl:

    module sample{ interface HelloWorld{ //二选一 wstring sayHello();//处理多字节的字符串,例如:中文 string sayHello();//处理ASCII类型的字符串 }; };

    此处的module就类似于C++的namespace,里面定义了一个接口HelloWorld。

    写好后在控制台执行    ps:在控制台执行下面所有文件都要在文件路径下进行!此处截图演示,后面也是一样的。

    idlj –fall HelloWorld.idl

    比如我的HelloWorld是放在桌面的HelloWorld文件夹里,那么就应该

    如果不进去会报错找不到文件

    运行完成后的控制台是这样的

    此时再看HelloWorld.idl所在的文件夹,已经多出来了一个文件夹

    里面有六个文件

    2.编写并编译服务端程序:HelloWorldServer.java

    代码如下

    import sample.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.CORBA.*; import org.omg.CORBA.portable.*; import org.omg.PortableServer.*; class HelloWorldServant extends HelloWorldPOA{ //对象实现类 //就算返回的字符串里有中文,也不用成public wstring sayHello()会报错找不到wstring类 public String sayHello(){ //return "\nHello World!\n"; return "\nHello World!\n软工菜鸡";//返回的字符串中有中文 } } public class HelloWorldServer{ //服务程序 public static void main(String args[]){ try{ //初始化ORB ORB orb = ORB.init(args, null); //取根POA的引用 org.omg.CORBA.Object poaobj = orb.resolve_initial_references ("RootPOA"); org.omg.PortableServer.POA rootPOA = org.omg.PortableServer.POAHelper.narrow(poaobj); org.omg.PortableServer.POAManager manager = rootPOA.the_POAManager(); //创建伺服对象 HelloWorldServant objRef = new HelloWorldServant(); HelloWorld obj = objRef._this(orb); //绑定命名服务 NamingContext ncRef = NamingContextHelper.narrow(orb.resolve_initial_references("NameService")); NameComponent nc = new NameComponent("Hello", ""); NameComponent path[] = {nc}; ncRef.rebind(path, obj); //激活POA管理器 manager.activate(); //等待处理客户程序的请求,运行成功的话在控制台显示此内容 System.out.println("HelloWorld is running!"); orb.run(); }catch (Exception e) { //运行失败捕获异常 System.err.println("ERROR: " + e); e.printStackTrace(System.out); } } }

    现在我们来分析一下HelloWorldServant,它作为对象实现类,主要作用是实现客户端的服务。它继承自HelloWorldPOA类,打开HelloWorldPOA.java我们可以看到

    public abstract class HelloWorldPOA extends org.omg.PortableServer.Servant

    它是一个抽象类,继承自一个Servant类。

    再看这一部分函数:

    public HelloWorld _this() { return HelloWorldHelper.narrow( super._this_object()); } public HelloWorld _this(org.omg.CORBA.ORB orb) { return HelloWorldHelper.narrow( super._this_object(orb)); }

    它们都返回了HelloWorldHelper中的narrow()函数,那么这个函数是干什么的呢?打开HelloWorldHelper.java,我们发现它里面首先定义了一个_id:

    private static String _id = "IDL:sample/HelloWorld:1.0";//IDL:接口描述语言

    找到narrow()函数,它的内容是:

    public static sample.HelloWorld narrow (org.omg.CORBA.Object obj) { if (obj == null) return null;//obj为空就返回null else if (obj instanceof sample.HelloWorld) return (sample.HelloWorld)obj;//如果obj是HelloWorld的一个实例就返回转换后的obj else if (!obj._is_a (id ())) throw new org.omg.CORBA.BAD_PARAM ();//我发现网上有好多人都遇到了这个异常 else { org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate (); sample._HelloWorldStub stub = new sample._HelloWorldStub (); stub._set_delegate(delegate); return stub; } }

    在百度第二个else if用法时我发现了好多人都遇到这个错,而且还没人解答,于是查找资料后我给出了一个解决错误的猜想:https://blog.csdn.net/d52370/article/details/90544386

    总的来说HelloWorldServant就是提供一个客户端实现的方法。

    编译HelloWorldServer。有警告不影响。

    这样就生成了HelloWorldServer和HelloWorldServant类

    同时我们也发现sample包里多了6个class

    3.编写并编译客户端程序: HelloWorldClient.java

    代码如下:

    import sample.*; import org.omg.CosNaming.*; import org.omg.CORBA.*; public class HelloWorldClient { public static void main(String args[]) { try{ ORB orb = ORB.init(args, null);//初始化一个ORB类 org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); NameComponent nc = new NameComponent("Hello",""); //定义一个组件 NameComponent path[] = {nc}; /*根据上面的分析ncRef.resolve(path)是sample.HelloWorld的一个实例,因此返回它被转化成的helloWorld类*/ HelloWorld helloWorld = HelloWorldHelper.narrow(ncRef.resolve(path)); String hello = helloWorld.sayHello(); System.out.println(hello); //输出sayHello()里面的内容,具体内容在Servant里面被定义 } catch (Exception e) {//捕获异常 System.out.println("ERROR : " + e) ; e.printStackTrace(System.out); } } }

    编译HelloWorldClient.java

    4.运行

    (1)在控制台当前路径下输入:

    tnameserv -ORBInitialPort 100

    启动名字服务器,数字是端口号,可以自己任意设置。

    显示是:

    (2)重新打开一个控制台,进入到文件所在路径,输入:

    java HelloWorldServer -ORBInitialPort 100

    启动服务端程序。

    显示是:

    (3)再打开一个控制台,进入到文件所在路径,输入:

    java HelloWorldClient -ORBInitialPort 100

    启动客户端程序。

    显示是: 

    【实例二:JAVA版CORBA程序2——Counter】

    这是一个计数器,它可以自增自减并输出自己的值。

    1.编写IDL接口counter.idl

    代码如下:

    module CounterApp{ interface Counter{ readonly attribute long value; //只读属性 void inc(); void dec(); }; };

    同样在控制台执行,我是在桌面建了一个Counter文件夹

    生成六个文件

    2.编写并编译对象实现代码:CounterImpl.java    //Impl是Implement的缩写

    代码如下:

    import CounterApp.*; public class CounterImpl extends CounterPOA { private int count; public CounterImpl(){ count = 0; //初始化 } public void inc(){ count++; //自加 } public void dec(){ count - -; //自减 } public int value(){ return count; //返回数值 } }

    编译它

    3.编写并编译服务端程序: Server.java

    代码如下:

    import CounterApp.*; import java.io.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.CORBA.*; import org.omg.CORBA.portable.*; import org.omg.PortableServer.*; public class Server { public static void main(String[] args){ try{ //初始化ORB ORB orb = ORB.init(args, null); //取根POA的引用 org.omg.CORBA.Object poaobj = orb.resolve_initial_references ("RootPOA"); org.omg.PortableServer.POA rootPOA = org.omg.PortableServer.POAHelper.narrow(poaobj); org.omg.PortableServer.POAManager manager = rootPOA.the_POAManager(); //创建伺服对象 CounterImpl c_impl = new CounterImpl(); Counter c = c_impl._this(orb); NamingContext ncRef = NamingContextHelper.narrow(orb.resolve_initial_references("NameService")); //绑定命名服务 NameComponent nc = new NameComponent("Count", ""); NameComponent path[] = {nc}; ncRef.rebind(path, c); //写入文件 FileOutputStream file = new FileOutputStream("Counter.ref");//把数字存进这个文件里面 PrintWriter writer = new PrintWriter(file); String ref = orb.object_to_string(c); writer.println(ref); writer.flush(); file.close(); //等待处理客户程序的请求 System.out.println("Server started."+" Stop:Ctrl-c"); rootPOA.the_POAManager().activate(); orb.run(); }catch(IOException ex){//捕获文件异常 System.out.println("File error:"+ex.getMessage()); System.exit(2); }catch(Exception ex){//捕获其他异常 System.out.println("Exception: "+ex.getMessage()); System.exit(1); } } }

    编译它

    4.编写并编译客户端程序: Client.java

    代码如下:

    import CounterApp.*; import java.util.*; import java.io.*; import org.omg.CORBA.*; import org.omg.CosNaming.*; public class Client { public static void main(String[] args){ try{ //初始化ORB ORB orb = ORB.init(args, null); //以下分析同实例一 org.omg.CORBA.Object obj = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(obj); NameComponent nc = new NameComponent("Count",""); NameComponent path[] = {nc}; String ref = null; try{ //从Counter.ref中读取数据 Scanner reader = new Scanner(new File("Counter.ref")); ref = reader.nextLine(); }catch(IOException ex){ System.out.println("File error: "+ex.getMessage()); System.exit(2); } obj = orb.string_to_object(ref); if(obj == null){ //初始化失败 System.out.println("Invalid IOR"); System.exit(4); } Counter c = null; try{ c = CounterHelper.narrow(obj); }catch(BAD_PARAM ex){ System.out.println("Narrowing failed"); System.exit(3); } int inp = -1; do{ System.out.print("Counter value: "+c.value()+"\nAction(+/-/e)?"); System.out.flush(); do{ try{ inp = System.in.read(); }catch(IOException ioe){} }while(inp != '+' && inp != '-' && inp != 'e'); if(inp == '+') c.inc(); //自加 else if(inp == '-') c.dec(); //自减 }while(inp != 'e'); }catch(Exception ex){ System.out.println("Exception: "+ex.getMessage()); //输入错误 System.exit(1); } } }

    编译它

    5.运行

    (1)在控制台的当前路径下运行,启动名字服务器

    tnameserv -ORBInitialPort 100

    (2)打开一个新的控制台,进入文件所在路径,运行

    java Server -ORBInitialPort 100

    启动服务端程序。

    此时按住Ctrl+c可结束服务

    (3)再打开一个新的控制台,进入文件所在路径,运行

    java Client -ORBInitialPort 100

    启动客户端程序。

    此时可进行操作了,输入"+"为自增输入"-"为自减输入"e"为退出

    同时我们可以发现已经生成了一个新的文件,也就是下次进入服务的Counter value会从这个文件里面读出,同时继续。

    三、结构组件图

     

    最新回复(0)