Java RMI远程异常

Java RMI远程异常,java,rmi,Java,Rmi,知道为什么我在尝试从Windows调用Unix计算机上的方法时会收到RemoteException吗? 我在网络中,不认为这是因为防火墙问题,因为在Unix机器上启动RMI服务器后,我可以从Windows“telnet”到Unix机器。我也不明白为什么它会成为本地环回IP 堆栈跟踪: RemoteException occured, details java.rmi.ConnectException: Connection refused to host: 127.0.0.1; nested e

知道为什么我在尝试从Windows调用Unix计算机上的方法时会收到RemoteException吗?
我在网络中,不认为这是因为防火墙问题,因为在Unix机器上启动RMI服务器后,我可以从Windows“telnet”到Unix机器。我也不明白为什么它会成为本地环回IP

堆栈跟踪:

RemoteException occured, details java.rmi.ConnectException: Connection refused to host: 127.0.0.1; nested exception is: 
    java.net.ConnectException: Connection refused: connect
java.rmi.ConnectException: Connection refused to host: 127.0.0.1; nested exception is: 
    java.net.ConnectException: Connection refused: connect

非常感谢。

您可能没有在Linux机器上正确配置主机名。我打赌,如果您从Linux设备中ping$(主机名),它将ping
127.0.0.1
。通常这是因为
/etc/hosts
文件中有一个条目

有两种方法可以解决这个问题。困难的方法是让Linux机器正确地将自己的主机名解析为IP地址。你可以编辑你的
/etc/hosts
文件,设置你的DNS服务器,无论你做什么。挑战在于,虽然这可能会使事情在技术上更加正确,但您可能会冒着破坏依赖于旧行为的事情的风险

更改最少的路径是Linux机箱的主机名或IP地址。(即,
java-Djava.rmi.server.hostname=$(主机名)…

为什么?

JavaRMI注册服务器实际上是一个网络范围的注册服务器。其他计算机上的对象可以将自己绑定到此注册表

注册远程对象时,注册包括网络地址作为注册的一部分。默认情况下,它使用的地址是“本地主机的IP地址,采用“虚线四元”格式”。在您的设置中,此地址是
127.0.0.1


当Windows box与注册服务联系以获取远程对象的地址时,它会返回
127.0.0.1
。然后,它尝试联系该地址的远程对象。这就是为什么它会指向环回地址。

我建议使用基于定制RMISocketFactory的解决方案

如Sun网站所述,您可以提供自己的SocketFactory:

我的解决方案使用这种机制来拦截客户端套接字的创建,并将接收到的主机(127.0.0.1)替换为客户端熟知的良好IP

其余的通信机制仍然基于JavaRMI标准

通过这种实现,导出器不必知道自己的IP,这有时并不容易(多个网络接口…)

下面是树类、工厂、服务器和客户机。Hello类和接口也被上传,以使其详尽无遗

希望它有用

袜子厂:

出口商:

客户:

豆子:

Impl:

最后也是最不重要的一点,java.policy:


您的客户机似乎认为您的服务器位于本地主机上,但如果没有更多详细信息,我无法说明原因。也许你可以发布你的客户端代码?它实际上与注册表没有任何关系。这只是关于存根中嵌入了什么信息。它可以在没有注册表的情况下发生。除此之外,戴夫的回答是正确的。最佳修复方法是更正/etc主机文件;解决方法是在服务器JVM上设置java.rmi.server.hostname。从根本上讲,这是某些Linux发行版的问题。这是Javadoc中RMI常见问题解答中的A.1项。嗨,Dave,我确实按照您所说的设置了系统属性,但我仍然得到相同的异常。虽然在进行更改之前,甚至在更改之后,我都能够找到注册表对象并成功地调用其上的list()方法。我想知道这个错误的原因是什么?@Gabriel-您是在服务器(Unix)端还是客户端(Windows)端设置了属性?应该在服务器端。请尝试IP地址,而不是
$(主机名)
我实际上只提供了IP地址。
import java.io.IOException;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.server.RMISocketFactory;

/**
 * Socket Factory for RMI calls.
 * 
 * This classe, instanciated from server when RMI objects are exported, is send
 * to the client who use it (transparently) for create sockets which call remote objects.
 * 
 * This implementation give the ability to modify dynamically the target host cible.
 * 
 * The host will not be aware of it's own IP.
 */
public class MySocketFactory extends RMISocketFactory implements Serializable {

    /**Target host for RMI calls, setted by caller. */
    private static String server = "localhost";

    /**
     * Create a client socket, replacing required host by the host setted when the service is called,
     * via {@link #setServer(String)}.
     * The host received is usually 127.0.0.1, depending on property java.rmi.server.hostname on the exporter.
     */
    @Override
    public Socket createSocket(String host, int port) throws IOException {
        System.out.println("change host from " + host + " to " + server);
        return getFactory().createSocket(server, port);
    }

    /**
     * Create a server socket.
     */
    @Override
    public ServerSocket createServerSocket(int port) throws IOException {
        return getFactory().createServerSocket(port);
    }

    /**
     * Use default RMI factory.
     */
    private RMISocketFactory getFactory() {
        return RMISocketFactory.getDefaultSocketFactory();
    }

    /**
     * Save the target host. This method must be called before use of a service (before Naming.lookup).
     */
    public static void setServer(String host) {
        server = host;
    }

}
import java.io.IOException;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RMISocketFactory;
import java.rmi.server.UnicastRemoteObject;

/**
 * RmiExport
 */
public class MyRmiExporter {

    /**
     * java -Djava.security.policy=java.policy MyRmiExporter
     */
    public static void main(String[] args) throws RemoteException, IOException {
        System.setSecurityManager(new RMISecurityManager());

        Hello export = new HelloImpl();
        RMISocketFactory sf = new MySocketFactory();

        UnicastRemoteObject.unexportObject(export, true);
        Remote stub = UnicastRemoteObject.exportObject(export, 0, sf, sf);
        String url = "rmi://0.0.0.0:" + Registry.REGISTRY_PORT + "/Hello";

        LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
        Naming.rebind(url, stub);

        System.out.println("Exported " + url);
    }

}
import java.io.IOException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.registry.Registry;

public class MyClient {

    /**
     * java MyClient localhost
     */
    public static void main(String[] args) throws IOException, NotBoundException, InterruptedException {
        String host = args[0];
        MySocketFactory.setServer(host);
        String url = "rmi://" + host + ":" + Registry.REGISTRY_PORT + "/Hello";;
        System.out.println("look up " + url);
        Hello proxy = (Hello) Naming.lookup(url);
        System.out.println("OK, remote getted !");
        System.out.println(proxy.hello("bonjour"));
    }
}
import java.io.Serializable;
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hello extends Remote, Serializable {

    String hello(String mess) throws RemoteException;

}
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class HelloImpl extends UnicastRemoteObject implements Hello {

    public HelloImpl() throws RemoteException {
    }

    @Override
    public String hello(String mess) throws RemoteException {
        return "hello : " + mess;
    }

}
grant {
    permission java.security.AllPermission;
};