RMI远程过程实现查询和操作远程的图数据

详细教程

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文件,键入相关权限即可解决问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值