实现一个计算引擎,当客户机把计算任务连同计算方法发给服务器时,服务器可以按照指定的计算方法把结 ![]() 果计算出来,并返回给客户机。 l、RMI系统由以下几个部分组成: 运行远程服务的服务器 需要远程服务的客户端程序 远程服务的接口定义(Remote Interface) 远程服务的实现(Remote Service) Stub和Skeleton文件 RMI命名服务,使得客户端可以发现远程服务 编写RMI过程 编写并编译接口的Java代码 编写并编译实现类的Java代码 利用RMIC从实现类产生的Stub和Skeleton类文件 启动注册服务 编写远程服务主机(host)程序的Java代码,运行之 开发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; } 远程接口实现: 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(); } 计算任务接口实现: 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; } } 客户机实现: 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 = "//" + 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开发上述各包,所以编译过程都省略不写了 生成stub和skel文件,以保证客户端和服务器之间通信 Ps: 在JDK1.5以下开发RMI时,直接编译所有的源文件,不用rmic ...Impl,就可以了。 要使用:rmic -v1.1 -keep XXXXXImpl 才会生成_Skel和_Stub。 运行RMI注册系统: 〉start rmiregistry (start可以另外重启一个进程,表现就是自动打开一个新的DOS窗口) 运行服务器: 〉java –Djava.security.policy=compute.policy engine.ComputeEngine(其中compute.policy是安全政策文件,表示该类执行的权限)compute.policy文件包含下列内容: grant{ permission java.security.AllPermission; }这个安全政策文件关闭检查权限,允许所有访问,是我们不需要考虑Java 2安全模型的细节。显然,生产环境中应使用更严格的安全策略文件。如果不设定并使用此安全文件,系统将提示错误:java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:1099 connect,resolve), 如果只把安全策略文件设计成 grant{ permission java.net.SocketPermission "localhost:1099", "connect, resolve"; };具体操作过程中还是会出现类似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)的错误 另外,关于此服务器的运行命令,有好多版本的说法,但试来试去作者还是认为只有上面列出的这个版本最好用。那些不好用的版本表现出来的症状是服务器运行起来后马上就停掉了,DOS界面一闪而过。起初没有发现这就是错误的征兆,后来在网上查到RMI注册机、服务器和客户机分别运行在三个不同的进程中,才意识到问题的严重性。 运行客户机: java -Djava.security.policy=compute.policy ComputeEngine localhost 1 2 运行结果就是上述两个加数的和。Done! 上面这些是我近一天工作的成果,虽然很辛苦,但是也还是觉得挺开心的,因为还是把问题一一解决了。至于那些书啊网啊,上面的说法真是纷繁复杂,不能不信,但也不能全信啊! |
|