【问题标题】:Java RMI address resolution issuesJava RMI 解决问题
【发布时间】:2012-09-26 15:22:47
【问题描述】:

我正在尝试重新编写一些基本的设计模式。只有代码 sn-ps 可供我使用,没有完整的运行代码示例。一种叫做代理模式。

我只想通过远程调用方法。这是我的简单代码:

WebService.java

public class WebService extends UnicastRemoteObject implements IRemote {

    private static final long serialVersionUID = 1L;

    public static void main(String[] args) {

        try {
            IRemote service = new WebService();
            Naming.rebind("RemoteCalculator", service);
        } catch (Exception e) {
            e.printStackTrace();
        }       
    }

    /** No arg default constructor */
    public WebService() throws RemoteException {    }

    /** Methods of remote interface */
    @Override
    public double getRoot(double v) throws RemoteException {        
        return Math.sqrt(v);
    }


}

... 其中 IRemote 是一个简单的接口,它扩展了远程接口并定义了单个示例方法 (getRoot(double)) 的签名。

现在是连接到远程的类:

TestProxy.java

public class TestProxy implements Remote{

    /**
     * @param args
     */
    public static void main(String[] args) {        
        new TestProxy().go(args[0]);
    }

    public TestProxy() {}

    public void go(String ip) {
        try {

            System.out.println("Trying to lookup for service ...");

            IRemote service = (IRemote) Naming.lookup("//" + ip + "/RemoteCalculator");

            System.out.println("done");

            double d = service.getRoot(5.0);

            System.out.println(d);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

我正在运行 rmiregistry.exe 并通过 rmic.exe 创建了我的 WebService_Stub.class,如一些文档中所示。 本地与 127.0.0.1 连接,因为(ip-)参数工作正常。但是,即使端口(1099)已打开并通过 telnet 进行检查,也无法通过 Internet 连接。

当我从命令行开始时:

java net.mypackage.remote.TestProxy 78.2.2.2

它总是给出结果:

尝试查找服务...完成 java.rmi.ConnectException: 连接拒绝主机:192.168.1.51;嵌套异常是: java.net.ConnectException:连接超时 在 sun.rmi.transport.tcp.TCPEndpoint.newSocket(未知来源) 在 sun.rmi.transport.tcp.TCPChannel.createConnection(未知来源) 在 sun.rmi.transport.tcp.TCPChannel.newConnection(未知来源) 在 sun.rmi.server.UnicastRef.invoke(未知来源) 在 java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unkn 自己的来源) 在 java.rmi.server.RemoteObjectInvocationHandler.invoke(未知来源) 在 $Proxy1.getRoot(未知来源) 在 net.gerdsmeier.remote.TestProxy.go(TestProxy.java:39) 在 net.gerdsmeier.remote.TestProxy.main(TestProxy.java:22) 引起:java.net.ConnectException:连接超时 在 java.net.PlainSocketImpl.socketConnect(本机方法) 在 java.net.AbstractPlainSocketImpl.doConnect(未知来源) 在 java.net.AbstractPlainSocketImpl.connectToAddress(未知来源) 在 java.net.AbstractPlainSocketImpl.connect(未知来源) 在 java.net.SocksSocketImpl.connect(未知来源) 在 java.net.Socket.connect(未知来源) 在 java.net.Socket.connect(未知来源) 在 java.net.Socket.(未知来源) 在 java.net.Socket.(未知来源) 在 sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(Unknown S 源) 在 sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(Unknown S 源) ... 9 更多

其中 192.168.1.51 是我的本地 IP 地址(即端口转发工作正常)。

【问题讨论】:

  • 你能发布整个异常堆栈吗?
  • 当然,我添加了剩余的行。

标签: java design-patterns rmi


【解决方案1】:

好的,我猜您的 WebService 在 NAT 之后,并且您在 1099 上设置了端口转发以通过 RMI 注册表。这还不够。远程对象将在与 1099 不同的端口上监听。如果您不设置端口转发到此端口,您将永远无法连接,因此double d = service.getRoot(5.0) 行出现异常。

问题是转发哪个端口?如果不指定端口,RMI 会随机选择一个高端口。但是您可以使用UnicastRemoteObject 构造函数的一个版本来指定端口。因此,您可以选择一个端口号,执行IRemote service = new WebService([portnumber]); 并在该端口上设置端口转发。

看看它是否会削减它!

【讨论】:

  • 您好 Maciej,首先感谢您的回答。我理解:一个端口用于服务请求,另一个端口用于每个具体的服务连接,对吗?我尝试通过在 WebService(int port) 构造函数中使用“super(port)”来扩展代码。这不起作用。
  • 哇,60 秒后我得到一个“完成”(见代码)。但尚未返回根目录。
  • 1099 只是为了获取远程对象的句柄。在这种情况下,它是 WebService。您在 IRemote service = (IRemote) Naming.lookup("//" + ip + "/RemoteCalculator"); 中使用 1099。这行得通。远程对象一经创建,就会开始监听一个端口,并且对该对象的所有请求都必须通过该端口。您可以发布您当前的代码吗?
  • 我改变的一次是 WebService.java 中的“public WebService(int port) throws RemoteException {super(port); }”。我将端口 1100 传递给这个构造函数。
  • 你的端口转发是如何配置的?
【解决方案2】:

好吧,我已经解决了一部分问题。它在服务器存根的逻辑背后:

在服务器端,我们必须通过添加行来添加有关全局主机名的信息

System.setProperty("java.rmi.server.hostname",Util.getGlobalAddress().getHostAddress());

... Util 类可能如下所示:

public class Util{

  /**
   * Finds this computer's global IP address
   * 
   * @return The global IP address, or null if a problem occurred
   */
  public static Inet4Address getGlobalAddress()
  {
    try
    {
      URLConnection uc = new URL( "http://vallentinsource.com/globalip.php" ).openConnection();
      BufferedReader br = new BufferedReader( new InputStreamReader( uc.getInputStream() ) );
      return ( Inet4Address ) InetAddress.getByName( br.readLine() );
    }
    catch( MalformedURLException e )
    {
      e.printStackTrace();
    }
    catch( IOException e )
    {
      e.printStackTrace();
    }

    return null;

  }
}

现在它朝一个方向工作,即像这样的客户端调用

service.printName("Pete");

在服务器端工作正常。另一方面...

d = service.getRoot(5.0);
System.out.println(d);

... 在客户端上还没有工作。它不会引发错误,但我们没有得到结果。然而。您也可以通过添加客户端 IP 地址/主机名来修复它:

System.setProperty("java.rmi.client.hostname", "ip.of.client.pc");

但是服务器不能事先知道所有的客户端地址。无论如何:这是一种解决方法,在某些情况下可能会有所帮助。

【讨论】:

  • 没有java.rmi.client.hostname 这样的东西。你编的。如果客户端导出回调,并且其默认 IP 地址不是可公开寻址的 IP 地址,则需要在客户端 JVM 中设置java.rmi.server.hostname
猜你喜欢
  • 1970-01-01
  • 2011-08-18
  • 1970-01-01
  • 1970-01-01
  • 2016-11-06
  • 2012-05-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多