1. 程式人生 > >用RMI進行遠端方法呼叫(2006-10-26 09:48:08)

用RMI進行遠端方法呼叫(2006-10-26 09:48:08)

用RMI進行遠端方法呼叫

(2006-10-26 09:48:08)

       遠端方法呼叫(RMI)機制可以把面向物件的思想進一步擴充套件,因為你可以呼叫的物件不僅可以在本機上,也可以在別的主機上。本文就簡單介紹rmi的程式設計方法。   首先介紹一些簡單的rmi的概念。  1, 伺服器和客戶:在rmi中,如果有一個物件進行遠端方法呼叫,這個物件就叫做客戶機物件,而遠端物件則被稱為伺服器物件。  2,建立伺服器物件的伺服器程式:這個程式用來建立伺服器物件,註冊這個物件,使得客戶可以通過註冊的名稱訪問伺服器物件。  3, 介面(interface),介面可以讓客戶端了解伺服器所能做的工作。更具體的說,就是它列出了可以在伺服器上執行的所有方法。客戶端程式必須能夠找到這個類,否則就不能執行對伺服器函式的呼叫。

  4, 客戶樁(stub),有的書中翻譯成為程式碼存根,它給客戶端程式提供一個樁,這個樁上""著伺服器物件。當客戶程式需要呼叫遠端物件時,這個樁被下載到客戶端(如果客戶端有這個類,則不需要下載)。然後客戶就可以像呼叫本地方法一樣呼叫遠端的方法了。  這個客戶樁的作用是將客戶向伺服器的請求進行編碼、進行傳輸,伺服器執行這次呼叫後將結果返回到客戶樁,客戶樁進行解碼,將解碼後的結果傳送到客戶程式中。對於編寫客戶端的程式設計師來說,他不需要知道其中的具體過程。  客戶樁不需要自己編寫,後面會說明它的生成方法。它實現了前述的介面(interface)。  下面就通過一個例子來說明編寫的過程。  1,編寫伺服器的介面:這一步是最主要的部分,因為介面是連線客戶機與伺服器的關鍵部分。在這個例子中,介面很簡單,程式碼如下:
import java.rmi.*;
  
public interface Product extends Remote
  
{
   
String getDescription() throws RemoteException;
  
}
  在這裡應注意的是,遠端物件的介面一定要擴充套件(extendJava.rmi包的Remote介面。同時介面中的所有的方法都要宣告丟擲RemoteException異常。這是因為由於網路連線的不可靠性,遠端方法呼叫很可能失敗。如果不宣告異常,在遠端方法呼叫失敗後,應用程式就會無法結束。
  2, 編寫伺服器物件:  Java中具有一個可以直接使用的伺服器類--UniCastRemoteObject
。它存在於Java.rmi.server包中。我們可以直接擴充套件這個類,使它實現前述的介面。這樣就可以使伺服器滿足我們的需要。
import java.rmi.server.*;
  
import java.rmi.*;
  
public class ProductImpl extends UnicastRemoteObject implements Product
  
{
   
public ProductImpl(String name) throws RemoteException
   
{
    
Desc = name;
   
}
   
public String getDescription() throws RemoteException
   
{
    
return "This is "+Desc+" product";
   
}
   
private String Desc;
  
}
  可以看到,rmi伺服器的實現和其他的方法程式碼沒有什麼不同。
  3,編寫建立伺服器物件的伺服器程式:import java.rmi.*;
  
public class ProductServer
  
{
   
public static void main(String[] args)
   
{
    
try
    
{
     
System.out.println("Constructin Server implementations ....");
     
ProductImpl p1 = new ProductImpl("toaster");
     
ProductImpl p2 = new ProductImpl("microwave");
     
System.out.println("Binding server implementations to registry");
     
Naming.rebind("toaster",p1);
     
Naming.rebind("microwave",p2);
     
System.out.println("waiting for clients...");
    
}catch(Exception e)
    
{
     
System.out.println("Error "+e);
    
}
   
}
  
}
  通過程式碼可以看到,這個伺服器首先建立了兩個伺服器物件。然後使用Naming.rebind()方法,將這個物件和一個名稱聯絡(繫結)在一起。這個名稱就是客戶機查詢伺服器物件所使用的名稱。Namingjava.rmi包中的類。這個類的作用是建立一套查詢物件的命名機制。通過它就可以將繫結在特定名稱上的物件找到。
  4, 編寫客戶端程式碼:import java.rmi.*;
  
import java.rmi.server.*;
  
public class ProductClient
  
{
   
public static void main(String[] args)
   
{
    
System.out.println("begin to invoke remote method");
    
System.setSecurityManager(new RMISecurityManager());
    
String url = "rmi://91.1.1.119:1099/";
    
try
    
{
     file://查詢遠端物件
System.out.println("1");
     
Product c1 = (Product)Naming.lookup(url + "toaster");
     
Product c2 = (Product)Naming.lookup(url + "microwave");
     file://呼叫遠端方法
System.out.println("2");
     
System.out.println(c1.getDescription());
     
System.out.println("3");
     
System.out.println(c2.getDescription());
    
}catch (Exception ex)
    
{
     
System.out.println("error "+ex);
    
}
   
}
  
}
  在這段程式碼中,首先定義了一個字串url。這個字串中儲存了找到遠端伺服器物件的協議和地址資訊。在rmi中,所使用的協議是rmi,埠號是1099。這個例子中,我的伺服器物件存放在ip地址為91.1.1.119的主機上,所以,這個字串的值為rmi://91.1.1.119:1099/
  接著,使用Naming.lookup()方法查詢遠端物件。引數就是伺服器的位置資訊和伺服器物件所繫結的名稱。  這裡需要注意的是,通過lookup方法得到其實不是伺服器物件本身的引用,而是下載到客戶機上的客戶樁。但是,這個方法得到的是Object型別,要使用這個物件,必須將它型別轉換成伺服器所實現的介面型別。  隨後,就可以像呼叫本地方法一樣呼叫遠端方法。在這個例子中,遠端方法是getDescription()  因為這段程式碼是對遠端物件進行操作,所以,它被放到一個trycatch塊中,來捕獲遠端呼叫過程中的異常。  最後,就要將伺服器和客戶機部署到機器上。  1,將所有的類檔案編譯為class檔案。然後在dos方式下使用rmic ProductImpl
  就可以生成客戶樁,名為ProductImpl_Stub.class
  2,把客戶端程式碼和介面程式碼拷貝到客戶機器上。  3,執行rmiregistry程式,啟動註冊系統,使得伺服器可以註冊在機器上,以供客戶呼叫。  4,啟動http服務。將介面類和客戶樁類放在http伺服器上,使得客戶可以下載。假設這兩個檔案的下載目錄是http://91.1.1.119/download/
  5,使用
start java -Djava.rmi.server.codebase= http://91.1.1.119/download/ ProductServer
  執行建立伺服器物件的程式。
  其中的-Djava.rmi.server.codebase= http://91.1.1.119/download/ 指明客戶程式下載客戶樁的地址。  6,因為rmi有安全限制,所以在客戶端必須建立一個策略檔案。假設名為client.policy
  檔案的內容為
grant
  
{
   permission java.net.SocketPermission 
"91.1.1.119:1024-65535","connect";
   permission java.net.SocketPermission 
"91.1.1.119:80","connect";
  
};
  使用 start java -Djava.security.policy=client.policy ProductClient 啟動客戶端,客戶端就可以連線80埠(http埠)和102465535的埠(其中包含了rmi的預設埠1099)。之後就可以看到程式的執行結果。
  以上就是使用rmi進行遠端方法呼叫的基本過程。  但是,應該注意到,rmi有一個很大的限制,那就是隻能在java編寫的物件之間使用,如果要在不同的語言寫成的物件之間通訊,那就需要CORBA的幫助