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