《并行与分布式计算》实验六——Java RMI编程

这篇博文一个多月前就发表过,但因当时在课程上该实验还未结束提交而删除了;对老师教学造成的不便深感歉意;写这些不是为了什么,也知道自己写的不好,只是记录自己的学习心历路程,同时也当作一个笔记,将来翻看的时候,也能有所收获。


一、实验目的与要求

实验目的:理解JavaRMI的体系结构,熟悉Java RMI程序的编写。

实验要求:请独立完成本实验。

二、实验内容

1. 下面的代码是一个Java RMI程序的主要代码,根据这些代码构建一个Java RMI程序,要求能正常运行,并显示运行截图(包括服务器端和客户端)。

Java RMI ,即远程方法调用,和Java Socket相比,RMI也是C/S模式,但是Socket主要是为了客户端和服务器之间的相互发生消息/传输文件(通过输入/输出缓冲流),比如 多人聊天 这样的程序就用Socket来实现比较方便。 而RMI(Remote Method Invoke)远程方法调用,顾名思义,客户端可以通过网络(把参数以及方法名传给服务器)远程调用 服务器端的方法(服务器端接受到客服端的请求和传递过来的参数本地运行客户请求的方法),服务器运行方法后再将运行结果返回给客户端(通过网络)。Java RMI封装了具体实现的过程,对客户端来说,它就像是调用了一个自己本地的一个方法一样(尽管它自己没有这个方法)。简单来说,Java RMI 在服务器端声明了一个“RMI注册表“,把可以做为远程调用的一个对象和一个名字绑定在一起放入注册表中客户想要调用服务器上的远程对象(的方法),通过在注册表中查找名字(之前在服务器和对象绑定在一起的名字),获得一个远程对象(实例),可以调用该实例的所有方法,即实现了远程调用。

当然实际上Java RMI原理并不是以上说的那么简单,具体还涉及了很多更底层的东西,可以百度Java RMI有很多博客有讲解。

本实验第1小题的程序是 在服务器实现了两个方法:【发送消息】和【计算阶层】。在客户端,通过 参数-f 或-m来选择用哪个功能,然后调用服务器的方法。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // 接口  
  2. package ex.server;  
  3.   
  4. import java.rmi.Remote;  
  5. import java.rmi.RemoteException;  
  6.   
  7. public interface RMIExample extends Remote  
  8. {  
  9.         public String PostMsg(String strMsg) throws RemoteException;  
  10.         public long Factorial(long lVal) throws RemoteException;  
  11. }  

声明接口,RMIExample 继承于 Remote类

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // 接口实现类  
  2. package ex.server;  
  3. import java.rmi.RemoteException;  
  4. import java.rmi.server.UnicastRemoteObject;  
  5.   
  6. public class RMIExampleImpl extends UnicastRemoteObject implements RMIExample  
  7. {  
  8.     protected static String  m_strName;  
  9.   
  10.     public RMIExampleImpl() throws RemoteException  
  11.     {  
  12.         super(); // call base class constructor  
  13.     }  
  14.       
  15.     public String PostMsg(String strMsg) throws RemoteException  
  16.     {  
  17.         System.out.println("Server: PostMsg() invoked...");  
  18.         System.out.println("Server: Message > " + strMsg);  
  19.         return "The Message has been posted !";  
  20.     }  
  21.   
  22.     public long Factorial(long lVal) throws RemoteException  
  23.     {  
  24.         long lRes = FactorialEx(lVal);  
  25.         System.out.println("Server: Factorial() invoked...");  
  26.         System.out.println("Server: Factorial("+lVal+") = " + lRes);  
  27.         return lRes;  
  28.     }  
  29.       
  30.     protected long FactorialEx(long lVal)  
  31.     {  
  32.         if (lVal <= 1)  
  33.             return 1;  
  34.         else  
  35.             return lVal * FactorialEx(lVal-1);  
  36.     }  
  37.       
  38. }  

实现接口声明的两个方法,类继承于UnicastRemoteObject,说明该类自动成为可远程调用的类

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //服务器  
  2. package ex.server;  
  3. import java.rmi.Naming;  
  4. import java.rmi.registry.LocateRegistry;  
  5. import java.rmi.registry.Registry;  
  6.   
  7. public class RMIServer {  
  8.     public static void main(String argv[])  
  9.     {  
  10.         try  
  11.         {  
  12.             String m_strName = "TheRMIExample";  
  13.             System.out.println("Server: Registering RMIExampleImpl as \"" + m_strName +"\"");  
  14.             Registry registry = LocateRegistry.createRegistry(5678);  //声明注册表  
  15.             RMIExampleImpl Example = new RMIExampleImpl();  
  16.             String StrName = "rmi://localhost:5678/TheRMIExample";  
  17.             Naming.rebind(StrName, Example);  
  18.             System.out.println("Server: Ready...");  
  19.         }  
  20.         catch (Exception e)  
  21.         {  
  22.             System.out.println("Server: Failed to register RMIExampleImpl: " + e);  
  23.         }  
  24.     }  
  25. }  
服务器程序。LocateRegistry.createRegistry(5678)在端口5678声明了一个注册表,Naming.rebind将StingName和类RMIExampleImpl的一个对象Example绑定在一起并放入注册表。

注意,这个名字在注册表中是唯一的。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //客户端   
  2. package ex.server;  
  3. import java.rmi.Naming;  
  4.   
  5. public class RMIClient {  
  6.     /** 
  7.      * @param argv 
  8.      */  
  9.     public static void main(String argv[])  
  10.     {  
  11.         // Validate command line parameters  
  12.         if (argv.length < 2)  
  13.         {  
  14.             System.out.println("Usage: java RMIClient [-m \"MESSAGE\"] [-f INTEGER]");  
  15.             System.exit(1);  
  16.         }  
  17.   
  18.         // Command line option flags  
  19.         boolean bMessage = false;  
  20.         boolean bFactorial = false;  
  21.   
  22.         String strMsg = "No message.";  
  23.         long   lVal = 1;  
  24.   
  25.         // Determine data to be processed  
  26.         for (int i=0; i<argv.length; i++)  
  27.         {  
  28.             if (argv[i].equals("-m"))  
  29.             {  
  30.                 bMessage = true;  
  31.                 strMsg = argv[++i];  
  32.             }  
  33.             if (argv[i].equals("-f"))  
  34.             {  
  35.                 bFactorial = true;  
  36.                 lVal = Long.parseLong(argv[++i]);  
  37.             }  
  38.          }  
  39.   
  40.         //System.setSecurityManager(new RMISecurityManager());  
  41.         String strName = "rmi://localhost:5678/TheRMIExample";  
  42.         System.out.println("Client: Looking up " + strName + "...");  
  43.         RMIExample RemRMIExample = null;  
  44.         try  
  45.         {  
  46.             RemRMIExample = (RMIExample)Naming.lookup(strName); //注意这里是接口对象,不是实现类对象  
  47.         }  
  48.         catch (Exception e)  
  49.         {  
  50.             System.out.println("Client: Exception thrown looking up " + strName);  
  51.             System.exit(1);  
  52.         }  
  53.   
  54.         // Send a messge to the remote object  
  55.         if (bMessage)  
  56.         {  
  57.             try  
  58.             {  
  59.                 //if (!RemRMIExample.PostMsg(strMsg))  
  60.                    // System.out.println("Client: Remote PostMsg() call failed.");  
  61.                 System.out.println(RemRMIExample.PostMsg(strMsg));  
  62.             }  
  63.             catch (Exception e)  
  64.             {  
  65.                 System.out.println("Client: Exception thrown calling PostMsg()." + e);  
  66.                 System.exit(1);  
  67.             }  
  68.         }  
  69.   
  70.         // Calculate the factorial  
  71.         if (bFactorial)  
  72.         {  
  73.             try  
  74.             {  
  75.                 long lRes = RemRMIExample.Factorial(lVal);  
  76.                 System.out.println("Client: Factorial(" + lVal + ") = " + lRes);  
  77.             }  
  78.             catch (Exception e)  
  79.             {  
  80.                  System.out.println("Client: Excpetion thrown calling Factorial().");  
  81.                  System.exit(1);  
  82.             }  
  83.          }  
  84.     }  
  85. }  
客户端程序。 Naming.lookup(strName),通过名字查找对象。



2. 附件的zip文件中包含有几个java文件,但是要正常运行还需要一些代码,补充所需要的代码,使得这个Java RMI程序能够运行,并显示运行截图(包括服务器端和客户端)。

注意到,第一小题的一般Java RMI,只有客户端远程调用服务器对象,服务器并没有调用客户端的对象。但是,有些需求要求服务器也要调用客户端对象。
比如,假设有一种游戏,有一个角色是【法官】(相当于服务器),有一些角色【玩家】(相当于客户端),游戏规则是,玩家随时可能向法官询问信息(客户调用服务器对象)以做出下一步选择
,也可以设定让法官在某件事情发生时,特别的提醒一下他 (这时候,服务器就要调用到客户端对象了) 。这就是RMI回调。客户回调允许对象客户在远程回调对象服务器上注册自己(注释1),以便服务器可以在所等待事件发生时,向客户发起远程方法调用的一个特征。

注释1:一般来说,需要在服务器端建立一个列表,客户可以把自己的远程调用接口“注册”到这个列表中,可以使用vector。

由此可以知道,客户端也应该提供一个和服务器端类似的回调接口,同样实现了Remote接口

继承自UnicastRemotObject类,里面提供即将被服务器回调的方法(函数)。
本实验的第2小题,是一个简单RMI客户回调的样例。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //客户端接口  
  2. import java.rmi.Remote;  
  3. import java.rmi.RemoteException;  
  4.   
  5. public interface CallbackClientInterface extends Remote {  
  6.   
  7.     public String notifyMe(String message)throws RemoteException;  
  8.       
  9. }  

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //服务器接口  
  2. import java.rmi.Remote;  
  3. import java.rmi.RemoteException;  
  4.   
  5.   
  6. public interface CallbackServerInterface extends Remote {  
  7.   
  8.   
  9.     public String sayHello( ) throws RemoteException;  
  10.     public void registerForCallback(CallbackClientInterface callbackClientObject) throws RemoteException;  
  11.     //synchronized  
  12.     public void unregisterForCallback(CallbackClientInterface callbackClientObject) throws RemoteException;  
  13. }  

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //客户接口实现类  
  2. import java.rmi.*;  
  3. import java.rmi.server.*;  
  4.   
  5. /** 
  6.  * This class implements the remote interface  
  7.  * CallbackClientInterface. 
  8.  * @author M. L. Liu 
  9.  */  
  10.   
  11. public class CallbackClientImpl extends UnicastRemoteObject  
  12.      implements CallbackClientInterface {  
  13.     
  14.    public CallbackClientImpl() throws RemoteException {  
  15.       super( );  
  16.    }  
  17.   
  18.    public String notifyMe(String message){  
  19.       String returnMessage = "Call back received: " + message;  
  20.       System.out.println(returnMessage);  
  21.       return returnMessage;  
  22.    }        
  23.   
  24. }// end CallbackClientImpl class     


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //服务器接口实现类  
  2. import java.rmi.*;  
  3. import java.rmi.server.*;  
  4. import java.util.Vector;  
  5.   
  6. /** 
  7.  * This class implements the remote interface  
  8.  * CallbackServerInterface. 
  9.  * @author M. L. Liu 
  10. */  
  11.   
  12. public class CallbackServerImpl extends UnicastRemoteObject implements CallbackServerInterface {  
  13.    private Vector clientList;  
  14.    public CallbackServerImpl() throws RemoteException {  
  15.       super( );  
  16.      clientList = new Vector();  
  17.    }  
  18.   
  19.   public String sayHello( ) throws RemoteException {  
  20.       return("hello");  
  21.   }  
  22.   
  23.   public synchronized void registerForCallback(CallbackClientInterface callbackClientObject)  
  24.     throws RemoteException{  
  25.       // store the callback object into the vector  
  26.       if (!(clientList.contains(callbackClientObject))) {  
  27.          clientList.addElement(callbackClientObject);  
  28.       System.out.println("Registered new client ");  
  29.       doCallbacks();   //在注册的同时就回调!  
  30.     } // end if  
  31.   }    
  32.   
  33. // This remote method allows an object client to   
  34. // cancel its registration for callback  
  35. // @param id is an ID for the client; to be used by  
  36. // the server to uniquely identify the registered client.  
  37.   public synchronized void unregisterForCallback(CallbackClientInterface callbackClientObject)   
  38.     throws RemoteException{  
  39.     if (clientList.removeElement(callbackClientObject)) {  
  40.       System.out.println("Unregistered client ");  
  41.     } else {  
  42.        System.out.println(  
  43.          "unregister: clientwasn't registered.");  
  44.     }  
  45.   }   
  46.   
  47.   private synchronized void doCallbacks( ) throws java.rmi.RemoteException{   
  48.     // make callback to each registered client  
  49.     System.out.println(  
  50.        "**************************************\n"  
  51.         + "Callbacks initiated ---");  
  52.     for (int i = 0; i < clientList.size(); i++){  
  53.       System.out.println("doing "+ i +"-th callback\n");      
  54.       // convert the vector object to a callback object  
  55.       CallbackClientInterface nextClient = (CallbackClientInterface)clientList.elementAt(i);  //从注册列表中获得客户端对象  
  56.       // invoke the callback method  
  57.         nextClient.notifyMe("Number of registered clients = " +  clientList.size()); //调用客户端方法,即回调  
  58.     }// end for  
  59.     System.out.println("********************************\n" + "Server completed callbacks ---");  
  60.   } // doCallbacks  
  61.   
  62. }// end CallbackServerImpl class     

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //服务器程序  
  2. import java.rmi.*;  
  3. import java.rmi.registry.Registry;  
  4. import java.rmi.registry.LocateRegistry;  
  5. import java.io.*;  
  6.   
  7. /** 
  8.  * This class represents the object server for a distributed 
  9.  * object of class Callback, which implements the remote  
  10.  * interface CallbackInterface. 
  11.  * @author M. L. Liu 
  12.  */  
  13.   
  14. public class CallbackServer{  
  15.       
  16.     public static void main(String args[]) {  
  17.         InputStreamReader is = new InputStreamReader(System.in);  
  18.         BufferedReader br = new BufferedReader(is);  
  19.         String portNum, registryURL;  
  20.         try{       
  21.             System.out.println("Enter the RMIregistry port number:");  
  22.             portNum = (br.readLine()).trim();  
  23.             int RMIPortNum = Integer.valueOf(portNum);  
  24.             startRegistry(RMIPortNum);                                  //关键语句  
  25.             CallbackServerImpl exportedObj =  new CallbackServerImpl();  
  26.             registryURL =  "rmi://localhost:" + portNum + "/callback";    
  27.             Naming.rebind(registryURL, exportedObj);                    //关键语句  
  28.             System.out.println("Callback Server ready.");  
  29.         }  
  30.         catch (Exception re) {  
  31.             System.out.println("Exception in HelloServer.main: " + re);  
  32.         }   
  33.     }   
  34.   //This method starts a RMI registry on the local host, if  
  35.   //it does not already exists at the specified port number.  
  36.   private static void startRegistry(int RMIPortNum)  
  37.     throws RemoteException{  
  38.     try {  
  39.       Registry registry = LocateRegistry.getRegistry(RMIPortNum);  
  40.       registry.list( );    
  41.         // This call will throw an exception  
  42.         // if the registry does not already exist  
  43.     }  
  44.     catch (RemoteException e) {   
  45.       // No valid registry at that port.  
  46.       Registry registry = LocateRegistry.createRegistry(RMIPortNum);  
  47.     }  
  48.   } // end startRegistry  
  49.   
  50. // end class  

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //客户端程序  
  2. import java.io.*;  
  3. import java.rmi.*;  
  4.   
  5. /** 
  6.  * This class represents the object client for a 
  7.  * distributed object of class CallbackServerImpl,  
  8.  * which implements the remote interface  
  9.  * CallbackServerInterface.  It also accepts callback 
  10.  * from the server. 
  11.  *  
  12.  * @author M. L. Liu 
  13.  */  
  14.   
  15. public class CallbackClient {  
  16.   
  17.   public static void main(String args[]) {  
  18.     try {  
  19.       int RMIPort;           
  20.       String hostName;  
  21.       InputStreamReader is =  new InputStreamReader(System.in);  
  22.       BufferedReader br = new BufferedReader(is);  
  23.       System.out.println("Enter the RMIRegistry host namer:");  
  24.       hostName = br.readLine();  
  25.       System.out.println("Enter the RMIregistry port number:");  
  26.       String portNum = br.readLine();  
  27.       RMIPort = Integer.parseInt(portNum);   
  28.       System.out.println("Enter how many seconds to stay registered:");  
  29.       String timeDuration = br.readLine();  
  30.       int time = Integer.parseInt(timeDuration);  
  31.       String registryURL = "rmi://localhost:" + portNum + "/callback";    
  32.       // find the remote object and cast it to an interface object  
  33.       CallbackServerInterface h =(CallbackServerInterface)Naming.lookup(registryURL);  //远程调用服务器,获得一个远程对象  
  34.       System.out.println("Lookup completed ");  
  35.       System.out.println("Server said " + h.sayHello());  //远程调用服务器对象方法,并输出获取的返回值  
  36.       CallbackClientInterface callbackObj = new CallbackClientImpl();  
  37.       // register for callback  
  38.       h.registerForCallback(callbackObj);  //在服务器上在注册一个回调  
  39.       System.out.println("Registered for callback.");  
  40.       try {  
  41.         Thread.sleep(time * 1000);  
  42.       }  
  43.       catch (InterruptedException ex){ // sleep over  
  44.       }  
  45.       h.unregisterForCallback(callbackObj);  
  46.       System.out.println("Unregistered for callback.");  
  47.     } // end try   
  48.     catch (Exception e) {  
  49.       System.out.println("Exception in CallbackClient: " + e);  
  50.     } // end catch  
  51.   } //end main  
  52. }//end class  



3. 编写一个Java RMI程序,服务器可以将一个英文单词翻译为中文,客户端可以输入一个英文单词,然后调用服务器的这个功能完成翻译。英文单词的中英文对照如附件1000words.txt所示。显示程序关键代码和运行截图。

这题比较简单,最普通的RMI调用,注意在服务器实现一下翻译功能的函数就行了。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //定义接口  
  2. import java.rmi.Remote;  
  3. import java.rmi.RemoteException;  
  4.   
  5. public interface TransInterfcae extends Remote{  
  6.   
  7.     public String getChinese(String str) throws RemoteException;  
  8. }  

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //接口实现  
  2. import java.io.BufferedReader;  
  3. import java.io.FileNotFoundException;  
  4. import java.io.FileReader;  
  5. import java.io.IOException;  
  6. import java.rmi.RemoteException;  
  7. import java.rmi.server.UnicastRemoteObject;  
  8. import java.util.*;  
  9.   
  10. public class TransImpl extends UnicastRemoteObject implements TransInterfcae  
  11. {  
  12.     HashMap <String,String> map = new HashMap<String,String>();  
  13.     public  TransImpl () throws RemoteException,FileNotFoundException  
  14.     {  
  15.         init();  
  16.     }  
  17.     public String getChinese(String str)  
  18.     {  
  19.         String ans = map.get(str);  
  20.         if(ans == null)  
  21.             return "Sorrry, this word is not within 1000 words";  
  22.         return ans;  
  23.     }  
  24.     public void init() throws FileNotFoundException  
  25.     {  
  26.         map.clear();  
  27.         try  
  28.         {  
  29.             BufferedReader reader = new BufferedReader(new FileReader("1000words.txt"));  
  30.             String str,key,value;  
  31.             while( (str = reader.readLine()) != null)  
  32.             {  
  33.                 key = "";  
  34.                 StringTokenizer st = new StringTokenizer(str);  
  35.                 value = st.nextToken();    
  36.                 while(st.hasMoreTokens()) //Fuck……有几个英文不止一个单词  
  37.                 {                     
  38.                     key = key + " " + st.nextToken();  
  39.                 }  
  40.                 //System.out.println(key.trim());  
  41.                 map.put(key.trim(), value);   
  42.             }  
  43.             reader.close();  
  44.         }  
  45.         catch (IOException e1) {  
  46.             e1.printStackTrace();  
  47.         }   
  48.           
  49.           
  50.     }  
  51. }  


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //服务器  
  2. import java.rmi.Naming;  
  3. import java.rmi.registry.LocateRegistry;  
  4.   
  5.   
  6. public class Server {  
  7.       
  8.     public static void main(String argv[])  
  9.     {  
  10.         try  
  11.         {  
  12.             //System.out.println("服务器准备就绪,可接受翻译!");  
  13.             LocateRegistry.createRegistry(4567);  
  14.             TransImpl Example = new TransImpl();  
  15.             String StrName = "rmi://localhost/translation";  
  16.             Naming.rebind(StrName, Example);  
  17.             System.out.println("Server: Ready...");  
  18.         }  
  19.         catch (Exception e)  
  20.         {  
  21.             System.out.println("Server: Failed to register RMIExampleImpl: " + e);  
  22.         }  
  23.     }  
  24. }  

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //客户端  
  2. import java.io.BufferedReader;  
  3. import java.io.IOException;  
  4. import java.io.InputStreamReader;  
  5. import java.rmi.Naming;  
  6.   
  7. public class Client {  
  8.   
  9.      public static void main(String argv[]) throws IOException  
  10.      {  
  11.          TransInterfcae t = null;  
  12.          try{  
  13.              t = (TransInterfcae) Naming.lookup("rmi://localhost:4567/translation");  
  14.          }  
  15.          catch (Exception e)  
  16.          {  
  17.              System.out.println("Client: Fail to lookup " + e);  
  18.             System.exit(1);  
  19.          }  
  20.          System.out.println("*******Game start*******");  
  21.          System.out.println("Please enter the words you want to translate: ");  
  22.          while(true)  
  23.          {  
  24.              BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
  25.              String key = br.readLine().trim();  
  26.              if(key.length() == 0 ) continue;  
  27.              if(key.equals("end"))  
  28.                  break;  
  29.              System.out.println(t.getChinese(key));  
  30.          }  
  31.          System.out.println("*******Game over*******");  
  32.      }  
  33. }  


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值