|
實現(xiàn)一個計算引擎,當客戶機把計算任務連同計算方法發(fā)給服務器時,服務器可以按照指定的計算方法把結(jié) ![]() 果計算出來,并返回給客戶機。 l、RMI系統(tǒng)由以下幾個部分組成: 運行遠程服務的服務器 需要遠程服務的客戶端程序 遠程服務的接口定義(Remote Interface) 遠程服務的實現(xiàn)(Remote Service) Stub和Skeleton文件 RMI命名服務,使得客戶端可以發(fā)現(xiàn)遠程服務 編寫RMI過程 編寫并編譯接口的Java代碼 編寫并編譯實現(xiàn)類的Java代碼 利用RMIC從實現(xiàn)類產(chǎn)生的Stub和Skeleton類文件 啟動注冊服務 編寫遠程服務主機(host)程序的Java代碼,運行之 開發(fā)RMI客戶端程序的Java代碼,運行之 l RMI提供的server和client信息傳遞機制稱為分布式對象應用 l 具體編碼過程: 遠程接口: package compute; import java.rmi.Remote; import java.rmi.RemoteException; public interface Compute extends Remote { Object executeTask(Task t)throws RemoteException; } 遠程接口實現(xiàn): package engine; import java.rmi.*; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.*; import compute.*; public class ComputeEngine extends UnicastRemoteObject implements Compute{
public ComputeEngine() throws RemoteException { super(); // TODO Auto-generated constructor stub } public Object executeTask(Task t) throws RemoteException { return t.execute(); } public static void main(String[] args) { if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } String name = "rmi://localhost:1099/Compute"; try { Compute engine = new ComputeEngine(); //Registry r = LocateRegistry.getRegistry("localhost",1099); Naming.rebind(name, engine); System.out.println("ComputeEngine bound"); }catch (Exception e) { System.err.println("ComputeEngine exception: " + e.getMessage()); e.printStackTrace(); } } } 計算任務接口: package compute; import java.io.Serializable; public interface Task extends Serializable { Object execute(); } 計算任務接口實現(xiàn): package client; import compute.*; import java.math.*; public class Add implements Task{ private int add1,add2; public Add(int add1, int add2) { this.add1 = add1; this.add2 = add2; } public Object execute() { int result = add1 + add2; Integer finalResult = new Integer(result); return finalResult; } } 客戶機實現(xiàn): package client; import java.rmi.*; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.math.*; import compute.*; public class ComputeAdd { public static void main(String args[]) { if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } try { String name = "rmi://"+args[0]+"/Compute"; Compute comp = (Compute) Naming.lookup(name); System.out.println(name); Add task = new Add(Integer.parseInt(args[1]),Integer.parseInt(args[2])); System.out.println(Integer.parseInt(args[1])+" "+Integer.parseInt(args[2])); Integer result = (Integer)(comp.executeTask(task)); System.out.println(result.toString()); } catch (Exception e) { e.printStackTrace(); System.err.println("Add exception: " + e.getMessage()); } } }package client; mport java.rmi.*; import java.math.*; import compute.*; public class ComputePi { public static void main(String args[]) { if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } try { String name = "http://" + args[0] + "/Compute"; Compute comp = (Compute) Naming.lookup(name); Pi task = new Pi(Integer.parseInt(args[1])); BigDecimal pi = (BigDecimal) (comp.executeTask(task)); System.out.println(pi); } catch (Exception e) { System.err.println("ComputePi exception: " + e.getMessage()); e.printStackTrace(); } } l 具體編譯與運行過程: 由于使用Eclipse開發(fā)上述各包,所以編譯過程都省略不寫了 生成stub和skel文件,以保證客戶端和服務器之間通信 Ps: 在JDK1.5以下開發(fā)RMI時,直接編譯所有的源文件,不用rmic ...Impl,就可以了。 要使用:rmic -v1.1 -keep XXXXXImpl 才會生成_Skel和_Stub。 運行RMI注冊系統(tǒng): 〉start rmiregistry (start可以另外重啟一個進程,表現(xiàn)就是自動打開一個新的DOS窗口) 運行服務器: 〉java –Djava.security.policy=compute.policy engine.ComputeEngine(其中compute.policy是安全政策文件,表示該類執(zhí)行的權(quán)限)compute.policy文件包含下列內(nèi)容: grant{ permission java.security.AllPermission; }這個安全政策文件關閉檢查權(quán)限,允許所有訪問,是我們不需要考慮Java 2安全模型的細節(jié)。顯然,生產(chǎn)環(huán)境中應使用更嚴格的安全策略文件。如果不設定并使用此安全文件,系統(tǒng)將提示錯誤:java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:1099 connect,resolve), 如果只把安全策略文件設計成 grant{ permission java.net.SocketPermission "localhost:1099", "connect, resolve"; };具體操作過程中還是會出現(xiàn)類似Exception in thread "RMI TCP Connection(2)-192.168.12.155" java.security.AccessControlException: access denied (java.net.SocketPermission 192.168.12.155:3576 accept,resolve)的錯誤 另外,關于此服務器的運行命令,有好多版本的說法,但試來試去作者還是認為只有上面列出的這個版本最好用。那些不好用的版本表現(xiàn)出來的癥狀是服務器運行起來后馬上就停掉了,DOS界面一閃而過。起初沒有發(fā)現(xiàn)這就是錯誤的征兆,后來在網(wǎng)上查到RMI注冊機、服務器和客戶機分別運行在三個不同的進程中,才意識到問題的嚴重性。 運行客戶機: java -Djava.security.policy=compute.policy ComputeEngine localhost 1 2 運行結(jié)果就是上述兩個加數(shù)的和。Done! 上面這些是我近一天工作的成果,雖然很辛苦,但是也還是覺得挺開心的,因為還是把問題一一解決了。至于那些書啊網(wǎng)啊,上面的說法真是紛繁復雜,不能不信,但也不能全信?。?/strong> |
|
|