實(shí)現(xiàn)一個(gè)計(jì)算引擎,當(dāng)客戶機(jī)把計(jì)算任務(wù)連同計(jì)算方法發(fā)給服務(wù)器時(shí),服務(wù)器可以按照指定的計(jì)算方法把結(jié) ![]() 果計(jì)算出來,并返回給客戶機(jī)。 l、RMI系統(tǒng)由以下幾個(gè)部分組成: 運(yùn)行遠(yuǎn)程服務(wù)的服務(wù)器 需要遠(yuǎn)程服務(wù)的客戶端程序 遠(yuǎn)程服務(wù)的接口定義(Remote Interface) 遠(yuǎn)程服務(wù)的實(shí)現(xiàn)(Remote Service) Stub和Skeleton文件 RMI命名服務(wù),使得客戶端可以發(fā)現(xiàn)遠(yuǎn)程服務(wù) 編寫RMI過程 編寫并編譯接口的Java代碼 編寫并編譯實(shí)現(xiàn)類的Java代碼 利用RMIC從實(shí)現(xiàn)類產(chǎn)生的Stub和Skeleton類文件 啟動(dòng)注冊服務(wù) 編寫遠(yuǎn)程服務(wù)主機(jī)(host)程序的Java代碼,運(yùn)行之 開發(fā)RMI客戶端程序的Java代碼,運(yùn)行之 l RMI提供的server和client信息傳遞機(jī)制稱為分布式對象應(yīng)用 l 具體編碼過程: 遠(yuǎn)程接口: package compute; import java.rmi.Remote; import java.rmi.RemoteException; public interface Compute extends Remote { Object executeTask(Task t)throws RemoteException; } 遠(yuǎn)程接口實(shí)現(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(); } } } 計(jì)算任務(wù)接口: package compute; import java.io.Serializable; public interface Task extends Serializable { Object execute(); } 計(jì)算任務(wù)接口實(shí)現(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; } } 客戶機(jī)實(shí)現(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 具體編譯與運(yùn)行過程: 由于使用Eclipse開發(fā)上述各包,所以編譯過程都省略不寫了 生成stub和skel文件,以保證客戶端和服務(wù)器之間通信 Ps: 在JDK1.5以下開發(fā)RMI時(shí),直接編譯所有的源文件,不用rmic ...Impl,就可以了。 要使用:rmic -v1.1 -keep XXXXXImpl 才會生成_Skel和_Stub。 運(yùn)行RMI注冊系統(tǒng): 〉start rmiregistry (start可以另外重啟一個(gè)進(jìn)程,表現(xiàn)就是自動(dòng)打開一個(gè)新的DOS窗口) 運(yùn)行服務(wù)器: 〉java –Djava.security.policy=compute.policy engine.ComputeEngine(其中compute.policy是安全政策文件,表示該類執(zhí)行的權(quán)限)compute.policy文件包含下列內(nèi)容: grant{ permission java.security.AllPermission; }這個(gè)安全政策文件關(guān)閉檢查權(quán)限,允許所有訪問,是我們不需要考慮Java 2安全模型的細(xì)節(jié)。顯然,生產(chǎn)環(huán)境中應(yīng)使用更嚴(yán)格的安全策略文件。如果不設(shè)定并使用此安全文件,系統(tǒng)將提示錯(cuò)誤:java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:1099 connect,resolve), 如果只把安全策略文件設(shè)計(jì)成 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)的錯(cuò)誤 另外,關(guān)于此服務(wù)器的運(yùn)行命令,有好多版本的說法,但試來試去作者還是認(rèn)為只有上面列出的這個(gè)版本最好用。那些不好用的版本表現(xiàn)出來的癥狀是服務(wù)器運(yùn)行起來后馬上就停掉了,DOS界面一閃而過。起初沒有發(fā)現(xiàn)這就是錯(cuò)誤的征兆,后來在網(wǎng)上查到RMI注冊機(jī)、服務(wù)器和客戶機(jī)分別運(yùn)行在三個(gè)不同的進(jìn)程中,才意識到問題的嚴(yán)重性。 運(yùn)行客戶機(jī): java -Djava.security.policy=compute.policy ComputeEngine localhost 1 2 運(yùn)行結(jié)果就是上述兩個(gè)加數(shù)的和。Done! 上面這些是我近一天工作的成果,雖然很辛苦,但是也還是覺得挺開心的,因?yàn)檫€是把問題一一解決了。至于那些書啊網(wǎng)啊,上面的說法真是紛繁復(fù)雜,不能不信,但也不能全信啊! |
|