posts - 495,comments - 227,trackbacks - 0
          一 .RMI概述
          RMI(Remote Method Invocation)
              RMI是分布式對象軟件包,它簡化了在多臺計算機上的JAVA應用之間的通信。必須在jdk1.1以上

          RMI用到的類
               java.rmi.Remote                   所有可以被遠程調用的對象都必須實現該接口
               java.rmi.server.UnicastRemoteObject  所有可以被遠程調用的對象都必須擴展該類
           
          什么是RMI
              遠程方法調用是一種計算機之間對象互相調用對方函數,啟動對方進程的一種機制,
          使用這種機制,某一臺計算機上的對象在調用另外一臺計算機上的方法時,使用的程
          序語法規則和在本地機上對象間的方法調用的語法規則一樣。

          優點
          這種機制給分布計算的系統設計、編程都帶來了極大的方便。
          只要按照RMI規則設計程序,可以不必再過問在RMI之下的網絡細節了,如:TCP和Socket等等。
          任意兩臺計算機之間的通訊完全由RMI負責。調用遠程計算機上的對象就像本地對象一樣方便。
           
          1、面向對象:
          RMI可將完整的對象作為參數和返回值進行傳遞,而不僅僅是預定義的數據類型。
          也就是說,可以將類似Java哈西表這樣的復雜類型作為一個參數進行傳遞。
           
          2、可移動屬性:
          RMI可將屬性從客戶機移動到服務器,或者從服務器移動到客戶機。
           
          3、設計方式:
          對象傳遞功能使您可以在分布式計算中充分利用面向對象技術的強大功能,如二層和三層結構系統。
          如果用戶能夠傳遞屬性,那么就可以在自己的解決方案中使用面向對象的設計方式。
          所有面向對象的設計方式無不依靠不同的屬性來發揮功能,如果不能傳遞完整的對象——包括實現和類型
          ——就會失去設計方式上所提供的優點。
           
          4、安全性:
          RMI使用Java內置的安全機制保證下載執行程序時用戶系統的安全。
          RMI使用專門為保護系統免遭惡意小程序侵害而設計的安全管理程序。
          5、便于編寫和使用
          RMI使得Java遠程服務程序和訪問這些服務程序的Java客戶程序的編寫工作變得輕松、簡單。
          遠程接口實際上就是Java接口。
          為了實現RMI的功能必須創建遠程對象任何可以被遠程調用的對象必須實現遠程接口。但遠程
          接口本身并不包含任何方法。因而需要創建一個新的接口來擴展遠程接口。
          新接口將包含所有可以遠程調用的方法。遠程對象必須實現這個新接口,由于新的接口擴展了
          遠程接口,實現了新接口,就滿足了遠程對象對實現遠程接口的要求,所實現的每個對象都將
          作為遠程對象引用。
           
          個人總結:
              RMI說白了,就是提供了一種遠程的方法調用。 這種調用簡單方便,可以傳遞復雜java對象。現在流行的j2ee中的EJB的底層實現技術就是RMI,EJB的調用就是經過封裝的,更高級的RMI調用。


          下面我們就來寫一個RMI的程序:
           
          一.創建RMI程序的6個步驟:
          1、定義一個遠程接口的接口,該接口中的每一個方法必須聲明它將產生一個RemoteException異常。
          2、定義一個實現該接口的類。
          3、使用RMIC程序生成遠程實現所需的殘根和框架。
          4、創建一個服務器,用于發布2中寫好的類。
          5. 創建一個客戶程序進行RMI調用。
          6、啟動rmiRegistry并運行自己的遠程服務器和客戶程序。
           
          二. 程序詳細說明
           
          1.定義一個遠程接口的接口,該接口中的每一個方法必須聲明它將產生一個RemoteException異常。
           
          import java.rmi.Remote;
          import java.rmi.RemoteException;
          public interface I_Hello extends java.rmi.Remote   //需要從Remote繼承
          {
                 public String SayHello() throws RemoteException;   //需要拋出remote異常
          }

             上面例子我們定義一個返回字符串的遠程方法 SayHello(),這個遠程接口 I_Hello必須是public的 ,它必須從java.rmi.Remote繼承而來,接口中的每一個方法都必須拋出遠程異常java.rmi.RemoteException。

          拋出這個異常的原因
          由于任何遠程方法調用實際上要進行許多低級網絡操作,因此網絡錯誤可能在調用過程中隨時發生。
          因此,所有的RMI操作都應放到try-catch塊中。
            
          2、定義一個實現該接口的類。
           
           import java.io.PrintStream;
          import java.rmi.*;
          import java.rmi.server.UnicastRemoteObject;
           
          public class Hello extends UnicastRemoteObject   //必須從UnicastRemoteObject  繼承
                             implements I_Hello
          {
                  public Hello() throws RemoteException     //需要一個拋出Remote異常的默認初始化方法
                  {
                  }
           
                  public String SayHello()     //這個是實現I_Hello接口的方法
                  {
                     return "Hello world !!";
                  }
          }
           
          實現接口的類必須繼承UnicastRemoteObject類。
          擴展java.rmi.server.UnicastRemoteObject
          UnicastRemoteObject顧名思義,是讓客戶機與服務器對象實例建立一對一的連接。
           
          3、使用RMIC程序生成遠程實現所需的殘根Stub 和 框架。
             2中的Hello 編譯好以后,我們就可以用RMIC命令來生成殘根Stub
             在Dos窗口里,到Hello.class 所在目錄,運行以下命令:
             rmic Hello
             
             命令執行完以后,將會在當前目錄生成一個 Hello_Stub.class 這個就是我們遠程調用時需要的類
           
          參考:
          在RMI中,客戶機上生成的調動調用參數和反調動返回值的代碼稱為殘根。有的書上稱這部分代碼為“主干”。
          服務器上生成的反調動調用參數和進行實際方法調用調動返回值的代碼稱為框架。
          生成殘根和框架的工具
          Rmic命令行工具(RMI Compiler)
          格式:
          Rmic classname
           
          4、創建一個服務器,用于發布2中寫好的類。
           
              import java.rmi.*;
          public class RMI_Server
          {
              public static void main(String[] args)
              {
                  try
                  {
                      Hello hello = new Hello();                //實例化要發布的類
                      Naming.rebind("RMI_Hello", hello);      //綁定RMI名稱 進行發布
                      System.out.println("=== Hello server Ready === ");
                  }
                  catch(Exception exception)
                  {
                      exception.printStackTrace();
                  }
              }
          }
           
          5. 創建一個客戶程序進行RMI調用。
           
          import java.rmi.*;
          public class RMI_Client {
              public static void main(String[] args) {
                  try
                  {
                     I_Hello hello = (I_Hello) Naming.lookup("RMI_Hello");  //通過RMI名稱查找遠程對象
                      System.out.println(hello.SayHello());                        //調用遠程對象的方法
                  } catch (Exception e)
                  {
                    e.printStackTrace();
                  }
              }

          }

          Naming.lookup("RMI_Hello") 其中的參數“RMI_Hello”只是針對本機的RMI查找,如果是異地的RMI調用請參照  rmi://127.0.0.1:1099/RMI_Hello       端口1099是默認的RMI端口,如果你啟動 rmiregistry 的時候(見第6點)沒有指定特殊的端口號,默認就是1099
           
          到此 我們 所有的代碼編寫都完成了,不過不要急著去運行,請跟隨第6點去運行,因為rmi 調用還會遇到一些特別的情況,偶花了牛勁,才找到原因的,許多剛用RMI的人,常常被這些問題搞得吐血
           
          6、啟動rmiRegistry并運行自己的遠程服務器和客戶程序。
           1)服務器的運行
              先在DOS下運行 rmiregistry     這個命令是開啟RMI的注冊服務,開啟以后我們的server程序才能調用rebing方法發布我們的類
           
              然后,運行我們的server程序  RMI_Server    這里是最容易出錯的,參見下面注意事項。
               注意:
                   如果提示找不到Stub類,這個需要用下面的命令來運行
           java.exe -Djava.rmi.server.codebase=file:/E:\MIS_Interface\momo\TestEasy\classes/  RMI_Server
           
          藍字部分指定了stub類的路徑。
           
            有人會問,我已經把stub 通過-classpath 加到類路徑里面了,為什么還沒有提示這個錯誤呢?原因是這樣的: 這里提示的找不到stub類,不是由你寫的RMI_Server這個程序引起的,是由rmi注冊服務器報告的異常,也就是我們前面啟動的 rmiregistry ,因為你寫的RMI_Server 要求RMI注冊服務器注冊一個新的類,自然RMI服務器必須知道你的類放在哪里,所以我們通過  -Djava.rmi.server.codebase 這個運行參數來指定
            你也可以通過修改操作系統的classpath 環境變量 來指定stub的位置,只不過太麻煩
           
          2) 客戶端的運行
                直接運行RMI_Client  即可  注意 把 Stub 和 接口 I_Hello 加到類路徑里
            
              通常第一次運行 客戶端都會報一個錯誤:   Access  XXXX 不記得具體的了,反正就是“訪問權限限制”, 這是因為RMI的服務需要授權,外部程序才能訪問,所以我們要改動 jre的安全配置文件,來開放權限,  具體如下:
           
             打開你的jdk目錄下的這個文件 C:\Program Files\Java\jdk1.5.0_04\jre\lib\security\java.policy
          在文件最后加入下面代碼:
           grant {
                     permission java.net.SocketPermission "*:1024-65535",
                          "connect,accept";
                     permission java.net.SocketPermission "*:80","connect";
                  };
          此代碼,開放了端口的connect訪問權限
           
          注意 你應該修改服務器那臺機子的安全配置文件,也就是你運行 rmiregistry 和 RMI_Server的機子
          另外,很多人修改完以后,仍然報這個錯誤,多數情況是由于你沒有修改到正確的jdk 下的文件,而是修改到其他jdk的文件, 我們安裝oracle , Weblogic等等軟件的時候都會自帶一個 jdk,他們會自動在操作系統的環境變量里面 加入jdk的路徑,所以,你先要確定你運行服務器端程序是用哪個jdk,再修改這個jdk下的配置文件,確定當前jdk的路徑很簡單  開始 -》運行-》rmiregistry 看看這個DOS窗口標題 的路徑,就是你當前系統默認jdk的路徑了
           
          客戶端正常運行以后,就會出現以下結果:
          Hello world !!

          這些字符是通過RMI調用遠程服務器的類返回的結果 

          RMI 實例

           

          Calculator.java

          import java.rmi.Remote;

          public interface Calculator  extends Remote 


           
              
          public long add(long a, long b)  throws java.rmi.RemoteException ;
           
              
          public long sub(long a, long b)  throws java.rmi.RemoteException ; 
             
              
          public long mul(long a, long b)  throws java.rmi.RemoteException ; 
              
              
          public long div(long a, long b)  throws java.rmi.RemoteException ; 
            
          }
           

          CalculatorClient.java:

          import java.rmi.Naming; 
          import java.rmi.RemoteException; 
          import java.net.MalformedURLException; 
          import java.rmi.NotBoundException; 

          public class CalculatorClient 

              
          public static void main(String[] args) 
                  
          try 
                   Calculator c 
          = (Calculator)
                                     Naming.lookup(
                           
          "rmi://localhost/CalculatorService"); 
                      System.out.println( c.sub(
          43) ); 
                      System.out.println( c.add(
          45) ); 
                      System.out.println( c.mul(
          36) ); 
                      System.out.println( c.div(
          93) ); 
                  }
           
                  
          catch (MalformedURLException murle) 
                      System.out.println(); 
                      System.out.println(
                        
          "MalformedURLException"); 
                      System.out.println(murle); 
                  }
           
                  
          catch (RemoteException re) 
                      System.out.println(); 
                      System.out.println(
                                  
          "RemoteException"); 
                      System.out.println(re); 
                  }
           
                  
          catch (NotBoundException nbe) 
                      System.out.println(); 
                      System.out.println(
                                 
          "NotBoundException"); 
                      System.out.println(nbe); 
                  }
           
                  
          catch (
                      java.lang.ArithmeticException
                                                ae) 

                      System.out.println(); 
                      System.out.println(
                       
          "java.lang.ArithmeticException"); 
                      System.out.println(ae); 
                  }
           
              }
           
          }
           


          CalculatorImpl.java:

          import java.rmi.server.UnicastRemoteObject;

          public class CalculatorImpl extends UnicastRemoteObject implements Calculator


              
          // 這個實現必須有一個顯式的構造函數,并且要拋出一個RemoteException異常 
              public CalculatorImpl() 
                  
          throws java.rmi.RemoteException 
                  
          super(); 
              }
           

              
          public long add(long a, long b) 
                  
          throws java.rmi.RemoteException 
                  
          return a + b; 
              }
           

              
          public long sub(long a, long b) 
                  
          throws java.rmi.RemoteException 
                  
          return a - b; 
              }
           

              
          public long mul(long a, long b) 
                  
          throws java.rmi.RemoteException 
                  
          return a * b; 
              }
           

              
          public long div(long a, long b) 
                  
          throws java.rmi.RemoteException 
                  
          return a / b; 
              }
           
          }
           


          CalculatorRemoteClient.java:


          import java.rmi.Naming; 
          import java.rmi.RemoteException; 
          import java.net.MalformedURLException; 
          import java.rmi.NotBoundException; 

          public class CalculatorRemoteClient 

              
          public static void main(String[] args) 
                  
          try 
                      Calculator c 
          = (Calculator)
                                     Naming.lookup(
                           
          "rmi://10.10.11.209/CalculatorService"); 
                      System.out.println( c.sub(
          43) ); 
                      System.out.println( c.add(
          45) ); 
                      System.out.println( c.mul(
          36) ); 
                      System.out.println( c.div(
          93) ); 
                  }
           
                  
          catch (MalformedURLException murle) 
                      System.out.println(); 
                      System.out.println(
                        
          "MalformedURLException"); 
                      System.out.println(murle); 
                  }
           
                  
          catch (RemoteException re) 
                      System.out.println(); 
                      System.out.println(
                                  
          "RemoteException"); 
                      System.out.println(re); 
                  }
           
                  
          catch (NotBoundException nbe) 
                      System.out.println(); 
                      System.out.println(
                                 
          "NotBoundException"); 
                      System.out.println(nbe); 
                  }
           
                  
          catch (
                      java.lang.ArithmeticException
                                                ae) 

                      System.out.println(); 
                      System.out.println(
                       
          "java.lang.ArithmeticException"); 
                      System.out.println(ae); 
                  }
           
              }
           
          }
           


          CalculatorServer.java:

          import java.rmi.Naming;

          public class CalculatorServer {

             
          public CalculatorServer() {
               
          try {
                 Calculator c 
          = new CalculatorImpl();
                 Naming.rebind(
          "rmi://localhost:1099/CalculatorService", c);
               }
           catch (Exception e) {
                 System.out.println(
          "Trouble: " + e);
               }

             }


             
          public static void main(String args[]) {
               
          new CalculatorServer();
             }

          }


           

          第二個

          服務端代碼

          Multi.java
          import java.rmi.*;

          public interface Multi extends Remote {
              
          int multi(int a, int b) throws RemoteException;
          }



          Plus.java
          import java.rmi.*;

          public interface Plus extends Remote{
              
          int plus(int a, int b) throws RemoteException;
          }


          MultiImpl.java
          import java.rmi.*;
          import java.rmi.server.UnicastRemoteObject;

          public class MultiImpl extends UnicastRemoteObject implements Multi{
              
          private String name;
              
          public MultiImpl(String s) throws Exception{
                  
          super();
                  name 
          = s;
              }

              
              
          public int multi(int a, int b) throws RemoteException {
                  System.out.println(
          "Invoke the multiply");
                  
          return (a * b);
              }

          }


          PlusImpl.java
          import java.rmi.*;
          import java.rmi.server.UnicastRemoteObject;

          public class PlusImpl extends UnicastRemoteObject implements Plus {
              
          private String name;
              
          public PlusImpl (String s) throws RemoteException {
                  
          super();
                  name 
          = s;
              }

              
              
          public int plus(int a, int b) throws RemoteException {
                  System.out.println(
          "Invoke the add");
                  
          return (a + b);
              }

          }


          CMSServer.java
          import java.rmi.*;

          public class CMSServer {
              
          public CMSServer(){
                  
          super();
              }

              
              
          public static void main (String[] args) {
                  
          //SYstem.setSecurityManager(new RMISecurityManager());
                  try{
                      
          new CMSServer();
                      MultiImpl mI 
          = new MultiImpl("MultiServer");
                      PlusImpl pI 
          = new PlusImpl("PlusServer");
                      
                      Naming.rebind(
          "pluscxx",pI);
                      Naming.rebind(
          "multicxx",mI);
                      System.out.println(
          "pluscxx and multicxx bound in registry");
                  
                  }
           catch(Exception e) {
                      System.out.println(
          "pluscxx and multicxx err: " + e.getMessage());
                  }

              }

          }


          客戶端代碼

          Multi.java
          import java.rmi.*;

          public interface Multi extends Remote {
              
          int multi(int a, int b) throws RemoteException;
          }


          Plus.java
          import java.rmi.*;

          public interface Plus extends Remote{
              
          int plus(int a, int b) throws RemoteException;
          }


          Frame1.java
          import java.awt.*;
          import java.rmi.*;
          import java.awt.event.*;
          import javax.swing.*;


          public class Frame1 extends JFrame {
              Container container;
              
              
          private JTextField jTextFields[];
              
          private JLabel jLabels[];
              
          private JButton jButton;
              
          private String[] labelsName = {"    Num1""    Num2""    Num3" ,"    plus then multiply" };
              
              
              
          public Frame1() {
                  
          super("sigle client multi server");
                  
          this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                  
          //enableEvents(AWTEvent.WINDOW_EVENT_MASK);
                  container = getContentPane();
                  container.setLayout(
          new GridLayout(5,2,10,10));
                  jLabels 
          = new JLabel[4];
                  jTextFields 
          = new JTextField[4];
                  
          int i = 0;
                  
          for(i = 0; i < 4; i++{
                      jLabels[i] 
          = new JLabel(labelsName[i]);
                      jTextFields[i] 
          = new JTextField("jTextField" + i);
                      
          //jTextFields[i].addActionListener(new Handler());
                      container.add(jLabels[i]);
                      container.add(jTextFields[i]);
                  }

                  jButton 
          = new JButton("Compute");
                  container.add(jButton);
                  jButton.addActionListener(
          new Handler());
                  
                  
          this.setSize(new Dimension(400300));
                  
          this.setVisible(true);
              }

              
              
          private class Handler implements ActionListener{
                  
          public void actionPerformed(ActionEvent ae) {
                      
          if(ae.getActionCommand().equals("Compute")) {
                          
          int[] num = new int [3];
                          
          int i = 0;
                          
          for(i = 0; i < 3; i++{
                              num[i] 
          = Integer.parseInt(jTextFields[i].getText());
                          }

                          
          try{
                              Plus p 
          = (Plus)Naming.lookup("pluscxx");
                              System.out.println(
          "Found plus object");    
                              
          int sum = p.plus(num[0], num[1]);
                              System.out.println(
          "Add the first two number");
                              Multi m 
          = (Multi)Naming.lookup("multicxx");
                              System.out.println(
          "Found multi object");
                              
          int multiply2 = m.multi(sum, num [2]);
                              System.out.println(
          "Multi with the last number");
                              System.out.println(
          "result is:" + multiply2);
                              jTextFields[
          3].setText("" + multiply2);
                              
          //container.validate();
                              System.out.println("OK");
                          }
           catch(Exception ex) {
                              System.out.println(ex.getMessage());
                          }

                      }

                  }
                  
              }

              
              
          public static void main(String[] args) {
                  
          new Frame1();
              }

          }



          引用地址:http://blog.csdn.net/tgeh23/archive/2008/03/14/2183746.aspx 

           

          posted on 2008-04-03 13:32 SIMONE 閱讀(1188) 評論(2)  編輯  收藏 所屬分類: rmi

          FeedBack:
          # re: java RMI 相關
          2011-12-02 15:56 | 勞資
          你這里好像有點小問題,我自己解決了,不錯。  回復  更多評論
            
          # re: java RMI 相關
          2013-08-22 16:32 | ekkny
          @勞資
          服務端和客戶端分離,怎么通信 ?  回復  更多評論
            

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 东宁县| 岳阳县| 永登县| 获嘉县| 张家口市| 房山区| 海林市| 夹江县| 平舆县| 临洮县| 屏南县| 青田县| 资溪县| 德州市| 南部县| 开远市| 玛多县| 达日县| 东丽区| 改则县| 永登县| 宜城市| 凤城市| 本溪| 益阳市| 潜山县| 莫力| 富裕县| 个旧市| 沅陵县| 古浪县| 乐陵市| 阳山县| 乌兰浩特市| 乌拉特前旗| 徐水县| 白城市| 六安市| 遂平县| 武定县| 同德县|