详细教程
RMI远程过程调用
-
引言
掌握远程过程调用原理,基于java RMI进行远程编程和控制。要求定义远程接口类及实现类:定义相应的处理方法;客户端利用RMI实现远程调用服务。同时,在在两台机器之间验证结果正确。
-
环境:
下载或安装java jdk (1.6或者以上);
熟悉IDEA 或者 eclipse 等开发环境;
查看附件示例文档和代码,在本地环境运行。
-
具体过程:
查询和操作远程的图数据(Graph):服务器端构建一个图结构,可基于https://jgrapht.org/进行操作(https://jgrapht.org/guide/UserOverview#hello-jgrapht)。然后客户端可以往这个图插入节点和边,可删除节点(附带删除边),并可查询图的节点数、边数,以及任意两个点的最短路径。返回服务器执行该操作所需要的时间、内存等信息。
-
导入所需的包,使用mavn即可,很方便。
-
改写hello接口,按照实验要求定义以下接口,即增加节点,增加边,查询当前节点与边,删除节点,查询最短路径:
/** * 增加顶点 * @param v * @return boolean * @throws java.rmi.RemoteException */ public boolean addVer(String v) throws java.rmi.RemoteException; /** * 增加边 * @param v1 * @param v2 * @return * @throws java.rmi.RemoteException */ public DefaultEdge addEdge(String v1, String v2)throws java.rmi.RemoteException; /** * 删除边 * @param v * @return * @throws java.rmi.RemoteException */ public boolean delVer(String v) throws java.rmi.RemoteException; /** * 查询顶点数和边数 * @return * @throws java.rmi.RemoteException */ public String check() throws java.rmi.RemoteException; /** * 查询最短路径 * @param v1 * @param v2 * @return * @throws java.rmi.RemoteException */ public String ShortestPath(String v1,String v2) throws java.rmi.RemoteException;
-
在helloimpl中实现上述接口,利用导入的图算法包,新建一个图对象,并利用已有的库函数进行上述接口的实现:
Graph<String, DefaultEdge> g; public HelloImpl(){ g=new DefaultDirectedGraph<>(DefaultEdge.class); } //增加节点 @Override public boolean addVer(String v) { return g.addVertex(v); } //增加边 @Override public DefaultEdge addEdge(String v1, String v2) { return g.addEdge(v1,v2); } //删除节点 @Override public boolean delVer(String v) { return g.removeVertex(v); } //查询节点数以及边数 @Override public String check() { return g.toString(); } //最短路径 @Override public String ShortestPath(String v1, String v2) { DijkstraShortestPath <String,DefaultEdge> dijkstraShortestPath = new DijkstraShortestPath<>(g); ShortestPathAlgorithm.SingleSourcePaths<String,DefaultEdge> ipaths=dijkstraShortestPath.getPaths(v1); return ipaths.getPath(v2).toString(); }
-
服务器端代码几乎无需修改,直接沿用原始代码即可。
-
客户端代码,我们要设计用户可以进行交互选择的命令行菜单,故需进行相应的分支条件的设计:
public class Client { private Client() { } public static void main(String[] args) throws RemoteException, MalformedURLException,NotBoundException { String host = (args.length < 1) ? "localhost" : args[0]; String name = (args.length == 2) ? args[1] : "World"; String urlo = "rmi://" + host + ":3333/Hello"; Hello stub = (Hello) Naming.lookup(urlo); System.out.println("link to the server: \n" + urlo); Registry registry = LocateRegistry.getRegistry(host); int i; Scanner input=new Scanner(System.in); do { System.out.println("0.退出程序"); System.out.println("1.增加节点"); System.out.println("2.增加边"); System.out.println("3.删除节点"); System.out.println("4.查询节点及边"); System.out.println("5.查询最短路径"); System.out.println("请输入你需要操作对应的编号"); i=input.nextInt(); switch (i){ case 0: break; case 1: System.out.println("请输入节点名"); String v=input.next(); if(stub.addVer(v)) { System.out.println("添加成功"); } else { System.out.println("添加失败"); } break; case 2: System.out.println("请输入你新增边的源顶点"); String v1=input.next(); System.out.println("请输入你新增边的终点"); String v2=input.next(); System.out.println(stub.addEdge(v1,v2)); break; case 3: System.out.println("请输入需要删除的节点"); String v3=input.next(); if(stub.delVer(v3)) { System.out.println("删除成功"); } else { System.out.println("删除失败"); } break; case 4: String gr=stub.check(); if(gr.length()==0) { System.out.println("空图"); } else { System.out.println(gr); } break; case 5: System.out.println("请输入起点"); String v4=input.next(); System.out.println("请输入终点"); String v5=input.next(); String path=stub.ShortestPath(v4,v5); if(path.length()>0) { System.out.println(path); } else { System.out.println("两点不同"); } break; default: System.out.println("输入有误,重新输入"); break; } } while (i!=0); } }
-
试运行:
添加节点
添加边,并查询当前节点以及边
-
> *查询当前节点与边,并查询最短路径*
> *删除节点后,再次查询当前节点以及边*
对RMI的远程过程调用有了较为深入的理解,并能够利用相关库自己搭建简单的远程掉调用的相关应用。
复习了图这种数据结构的最短路径等相关知识。
除此之外实验过程中还遇到了一些问题,在写好代码快进行测试时,发现服务器端跑不起来。如下图:
-
解决方法:
修改jre下的java.policy文件,键入相关权限即可解决问题。