瘋狂

          STANDING ON THE SHOULDERS OF GIANTS
          posts - 481, comments - 486, trackbacks - 0, articles - 1
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理
          場景:java RMI 在服務端者啟動360 wifi共享,報錯java.rmi.ConnectException: Connection refused to host: xx。
                   也就是服務端在調用時使用了wifi共享網卡的地址。此地址在RMI客戶端pc上無法ping通。(因為沒有連接此wifi。當然RMI客戶端pc如果連接此wifi是不會報錯的)。
          想關資料:

          http://docs.huihoo.com/java/rmi/whitepage/index.html
          比較全的解釋RMI的英文資料:http://docs.oracle.com/javase/1.5.0/docs/guide/rmi/faq.html#netunknownhost
          http://www.aygfsteel.com/shaolijun/archive/2007/05/22/119213.html

          測試代碼

          (一)服務端:
          • 服務接口
          import java.rmi.Remote;
          import java.rmi.RemoteException;
          /**
           * rmi remote 接口
           * 
          @author joe
           * @2014-12-5 @上午11:49:10
           
          */
          public interface RmiInterface extends Remote{
              
              public String say(String name) throws RemoteException;

          }
          • 接口實現
          import java.rmi.RemoteException;
          import java.rmi.server.UnicastRemoteObject;


          public class RmiServer extends UnicastRemoteObject implements RmiInterface{
              
              private static final long serialVersionUID = 1L;

              protected RmiServer() throws RemoteException {
                  super();
              }

              public String say(String name) throws RemoteException {
                  return "hello,"+name;
              }
          }
          • 發布服務
          public static void main(String[] args) throws MalformedURLException, RemoteException, AlreadyBoundException {
                  RmiServer server=new RmiServer();
                  LocateRegistry.createRegistry(8808);  
                  Naming.rebind("http://10.10.XX.XX:8808/SAMPLE-SERVER", server);  
              }

          (二)客戶端 調用服務:

          public static void main(String[] args) throws Exception {
                  RmiInterface server=(RmiInterface) Naming.lookup("http://10.10.116.XX:8808/SAMPLE-SERVER");
                  System.out.println(server.say("張三"));
              }

          此時報錯,java.rmi.ConnectException: Connection refused to host: 192.168.23.X。

          RMI的調用原理基本如下:

          大致翻譯如下:首先客戶端必須通過Naming.lookup得到服務端服務的一個指針或者叫指針,一旦擁有的這個應用,客戶端將使用服務的引用里面包含的主機名(ip)和端口來訪問服務。
              也就是說:雖然我們就服務端的IP和端口去Naming.lookup("http://10.10.116.XX:8808/SAMPLE-SERVER");,但是服務端返回的服務的引用里面包含的ip并不是lookup時的ip。
          官方說法:
          【In many versions of the JDK (all versions of the JDK except in v1.1 and the latest releases), Java RMI may default to using an unresolvable server hostname (for example: unqualified names, Windows Internet Naming Service (WINS) names, or unqualified DHCP names). When a Java RMI client invokes a remote method using a reference that contains an unresolvable server hostname, the client will throw an UnknownHostException.】

          In order to generate functional remote references, Java RMI servers must be able to supply a fully qualified hostname or IP address that is resolvable from all Java RMI clients (an example of a fully qualified hostname is foo.bar.com). If a Java RMI program provides a remote callback operation, then that program serves a Java RMI object and consequently, must be able to determine a resolvable hostname to use as its server hostname in the remote references it passes to Java RMI clients. VMs that make calls to applets that serve remote objects may throwUnknownHostExceptions because the applet has failed to provide a usable server hostname.

          If your Java RMI application throws an UnknownHostException, you can look at the resulting stack trace to see if the hostname that the client is using to contact its remote server is incorrect or not fully qualified.【 If necessary, you can set the java.rmi.server.hostname property on the server to the correct IP address or hostname of the server machine and Java RMI will use this property's value to generate remote references to the server.】

          解決辦法就是在服務端發布注冊服務的之前設置:
          System.setProperty("java.rmi.server.hostname", 指定IP);

          對應到本文例子就是:
          public static void main(String[] args) throws MalformedURLException, RemoteException, AlreadyBoundException {
                  RmiServer server=new RmiServer();
                  System.setProperty("java.rmi.server.hostname", 指定IP);
                  LocateRegistry.createRegistry(8808);  
                  Naming.rebind("http://10.10.116.74:8808/SAMPLE-SERVER", server);  
              }

          但是此時還是報相同的錯沒法訪問,百思不得其解,原來java.rmi.server.hostname的設置必須在服務對象創建之前。
          public static void main(String[] args) throws MalformedURLException, RemoteException, AlreadyBoundException {
                  System.setProperty("java.rmi.server.hostname", 指定IP);
                  RmiServer server=new RmiServer();
                  LocateRegistry.createRegistry(8808);  
                  Naming.rebind("http://10.10.116.74:8808/SAMPLE-SERVER", server);  
              }
          為什么呢:
              RmiServer 這個實現類使用了UnicastRemoteObject去聯接RMI系統。在我們的例子中,我們是直接的從UnicastRemoteObject這個類上繼承的,事實上并不一定要這樣做,當然也可以不是從UnicastRmeoteObject上繼承,那必須使用它的exportObject()方法去聯接到RMI。如果一個類繼承自UnicastRemoteObject,那么它必須提供一個構造函數并且聲明拋出一個RemoteException對象。當這個構造函數調用了super(),它久激活UnicastRemoteObject中的代碼完成RMI的連接和遠程對象的初始化。而此時應該已經決定了使用哪個hostname來實例化遠程對象。因此必須在服務對象創建之前指定綁定的hostname。

          ~~~完。
          主站蜘蛛池模板: 中西区| 长垣县| 临江市| 宁波市| 曲麻莱县| 富顺县| 河津市| 云南省| 贡嘎县| 浮梁县| 孟州市| 建始县| 旺苍县| 重庆市| 西安市| 田东县| 巴东县| 开化县| 汽车| 伊宁市| 普安县| 青州市| 长兴县| 新乐市| 水富县| 莆田市| 云龙县| 宿州市| 克什克腾旗| 武邑县| 剑阁县| 基隆市| 巩义市| 区。| 苏尼特右旗| 郸城县| 泰来县| 建德市| 永定县| 武隆县| 塔城市|