CORBA組件編程方法實例+分析

預警:本篇中有大量截圖+代碼/代碼段

關於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會從這個文件裏面讀出,同時繼續。

三、結構組件圖

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章