Java遠端呼叫

HotDog_發表於2017-02-27

主要參考

http://www.kaixinwenda.com/article-yxc135-7690958.html

http://bbs.chinaunix.NET/thread-1179312-1-1.html


Java 遠端處理 
   Java遠端方法呼叫(RMI)提供了Java程式語言的遠端通訊功能,這種特性使客戶機上執行的程式可以呼叫遠端伺服器上的物件,使Java程式設計人員能夠在網路環境中分佈操作。 
   建立一個簡單的Java分散式遠端方法呼叫程式可以按以下幾個步驟操作, 
   
   一、定義遠端介面: 
   在 Java 中,遠端物件是實現遠端介面的類的例項, 遠端介面宣告每個要遠端呼叫的方法。在需要建立一個遠端物件的時候,我們通過傳遞一個介面來隱藏基層的實施細節,客戶通過介面控制程式碼傳送訊息即可。 
   遠端介面具有如下特點: 
   1) 遠端介面必須為public屬性。如果不這樣,除非客戶端與遠端介面在同一個包內,否則 當試圖裝入實現該遠端介面的遠端物件時,呼叫會得到錯誤結果。 
   2) 遠端介面必須擴充套件介面java.rmi.Remote。 
   3) 除與應用程式本身特定的例外之外,遠端介面中的每個方法都必須在自己的throws從句中 宣告java.rmi.RemoteException。(或 RemoteException 的父類)。 
   4) 作為引數或返回值傳遞的一個遠端物件(不管是直接,還是本地物件中嵌入)必須宣告為遠 程介面,而不應宣告為實施類。 


下面是遠端介面的定義

[java] view plain copy
  1. package test;  
  2. import java.rmi.Remote;  
  3. import java.rmi.RemoteException;  
  4. import java.math.BigInteger;  
  5.   
  6. public interface Fib extends Remote {  
  7.     public int getFib(int n) throws RemoteException;  
  8. //    public BigInteger getFib(BigInteger n) throws RemoteException;  
  9. }  

二、實現遠端介面: 
   遠端物件實現類必須擴充套件遠端物件java.rmi.UnicastRemoteObject類,並實現所定義的遠端介面。遠端物件的實現類中包含實現每個遠端介面所指定的遠端方法的程式碼。這個類也可以含有附加的方法,但客戶只能使用遠端介面中的方法。因為客戶是指向介面的一個控制程式碼,而不是它的哪個類。必須為遠端物件定義建構函式,即使只准備定義一個預設建構函式,用它呼叫基礎類建構函式。因為基礎類建構函式可能會丟擲 java.rmi.RemoteException,所以即使別無它用必須丟擲java.rmi.RemoteException例外。 
   以下是遠端物件實現類的宣告:

[java] view plain copy
  1. package test;  
  2. import java.math.BigInteger;  
  3. import java.rmi.*;  
  4. import java.rmi.server.UnicastRemoteObject;  
  5.   
  6. public class FibImp extends UnicastRemoteObject implements Fib {  
  7.     public FibImp() throws RemoteException {  
  8.         super();  
  9.     }  
  10.       
  11.      
  12.     public int getFib(int n) throws RemoteException {  
  13.         return n+2;  
  14.     }  
  15.      
  16. }  

 三、編寫伺服器類: 
   包含 main 方法的類可以是實現類自身,也可以完全是另一個類。下面通過RmiSampleServer 來建立一個遠端物件的例項,並通過java.rmi.registry.LocateRegistry類的createRegistry 方法從指定埠號啟動註冊服務程式,也可以通過執行 rmiregistry 命令啟動註冊服務程式,註冊服務程式的預設執行埠為 1099。必須將遠端物件名字繫結到對遠端物件的引用上: Naming.rebind("//localhost:8808/SAMPLE-SERVER" , Server); 
   以下是伺服器類的宣告:


[java] view plain copy
  1. package test;  
  2. import java.net.MalformedURLException;  
  3. import java.rmi.Naming;  
  4. import java.rmi.RemoteException;  
  5. import java.rmi.registry.LocateRegistry;   
  6. public class FibonacciServer {  
  7.     /** 
  8.      * @param args 
  9.      */  
  10.     public static void main(String[] args) {  
  11.         try {  
  12.             LocateRegistry.createRegistry(8804);    
  13.             FibImp f = new FibImp();  
  14.               
  15.             // 註冊到 registry 中  
  16.             Naming.rebind("//localhost:8804/SAMPLE-SERVER", f);  
  17.             System.out.println("fib server ready");  
  18.               
  19.         } catch (RemoteException re) {  
  20.             System.out.println("Exception in FibonacciImpl.main: " + re);  
  21.         } catch (MalformedURLException e) {  
  22.             System.out.println("MalformedURLException " + e);  
  23.         }  
  24.     }  
  25. }  

 四、編寫使用遠端服務的客戶機類:
   客戶機類的主要功能有兩個,一是通過Naming.lookup方法來構造註冊服務程式 stub 程式例項,二是呼叫伺服器遠端物件上的遠端方法。 
   以下是客戶端類的宣告:

[java] view plain copy
  1. package testClient;  
  2.   
  3. import test.Fib;  
  4. import java.math.BigInteger;  
  5. import java.net.MalformedURLException;  
  6. import java.rmi.Naming;  
  7. import java.rmi.NotBoundException;  
  8. import java.rmi.RemoteException;  
  9. public class FibClient {  
  10.     /** 
  11.      * @param args 
  12.      */  
  13.     public static void main(String[] args) {  
  14.         String url = "//localhost:8804/SAMPLE-SERVER";  
  15.         try {  
  16.               
  17.             Fib calc = (Fib) Naming.lookup(url);  
  18.             for (int i = 0; i < 10; ++i) {  
  19.                 int f = calc.getFib(i);  
  20.                 System.out.println(f);  
  21.             }  
  22.         } catch (MalformedURLException e) {  
  23.             e.printStackTrace();  
  24.         } catch (RemoteException e) {  
  25.             e.printStackTrace();  
  26.         } catch (NotBoundException e) {  
  27.             e.printStackTrace();  
  28.         }  
  29.     }  
  30. }  

之前一直在eclipse下開發,對java的命令列編譯,執行不是很清楚,下面的編譯耗費了很多時間。

在包外面進行編譯

javac test/*.java

javac testClient/*.java


使用rmic編譯stub檔案,在jdk1.5以後,利用java的reflect機制,因此就不會生成skeleton檔案了

在windows下

執行rmic -classpath . test.FibImp,即可生成FibImp_Stub.class

Linux總是提示:/test/FibImp.class 中的類檔案格式無效。  major.minor 版本 "51.0" 太新,此工具無法識別。

還需要排查


啟動rmiregistry

直接輸入rmiregistry即可


執行伺服器:

java test.FibonacciServer


執行客戶機:

java testClient.FibClient



下面是用實驗室的Linux伺服器的操作過程

一臺伺服器編譯沒有問題,但是在rmic生成存根class時,出現的問題很蹊蹺,網上也搜不到:

error: ./test/FibImp.class 中的類檔案格式無效。  major.minor 版本 "51.0" 太新,此工具無法識別。
error: 未找到類 test.FibImp。

這類錯誤出現的原因是: major.minor 就像是我們可以這麼想像,同樣是微軟體的程式,32 位的應用程式不能拿到 16 位系統中執行那樣。


參見 http://www.blogjava.Net/Jay2009/archive/2009/04/23/267108.html


好吧,那就再換一臺linux伺服器


編譯就有問題,應該是環境變數的問題,在javac 之後新增 -classpath . 即可


javac -classpath . testClient/FibClient.java 


生成存根

rmic -classpath . test.FibImp



在執行程式的時候也要在java 後面新增-classpath .

相關文章