java RMI 远程异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2748259/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
RMI RemoteException
提问by Gaurav Panwar
Any idea why do I get RemoteException while trying to invoke methods on Unix machine from Windows?
I am inside the network and don't think this is because of firewall problem as I can do "telnet" from Windows to Unix box after starting the RMI server at the unix box. I also could not understand why is it going to local loopback IP?
知道为什么在尝试从 Windows 调用 Unix 机器上的方法时会得到 RemoteException 吗?
我在网络内部,不认为这是因为防火墙问题,因为在 unix 机器上启动 RMI 服务器后,我可以从 Windows 到 Unix 机器执行“telnet”。我也不明白为什么要本地环回IP?
Stack Trace:
堆栈跟踪:
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
Many thanks in advance.
提前谢谢了。
回答by leedm777
You probably don't have your hostname configured properly on your Linux box. I bet if you ping $(hostname)from your Linux box, it will ping 127.0.0.1. Usually this is because of an entry in your /etc/hostsfile.
您可能没有在 Linux 机器上正确配置主机名。我敢打赌,如果你ping $(hostname)在你的 Linux 机器上,它会 ping 127.0.0.1。通常这是因为您的/etc/hosts文件中有一个条目。
There's a couple of ways to solve the problem. The hard way would be to get your Linux box to resolve its own hostname to its IP address properly. You can edit your /etc/hostsfile, setup your DNS server, whatever you've got to do. The challenge is that while this may make things more technically correct, you run the risk of breaking things that relied on the old behavior.
有几种方法可以解决这个问题。困难的方法是让你的 Linux 机器正确地将它自己的主机名解析为它的 IP 地址。您可以编辑您的/etc/hosts文件,设置您的 DNS 服务器,无论您需要做什么。挑战在于,虽然这可能会使事情在技术上更加正确,但您可能会破坏依赖于旧行为的事物。
The path of least change would be to set the system property java.rmi.server.hostnameto the hostname or IP address of your Linux box. (i.e. java -Djava.rmi.server.hostname=$(hostname) ...).
更改最少的路径是将系统属性设置为java.rmi.server.hostnameLinux 机器的主机名或 IP 地址。(即java -Djava.rmi.server.hostname=$(hostname) ...)。
Why?
为什么?
The Java RMI registration server is actually a network wide registration server. Objects on other machines can bind themselves to this registry.
Java RMI 注册服务器实际上是一个网络范围的注册服务器。其他机器上的对象可以将自己绑定到此注册表。
When a remote object is registered, the registration includes the network address as part of the registration. By default, the address it uses is 'the IP address of the local host, in "dotted-quad" format.' In your setup, this address is 127.0.0.1.
当注册远程对象时,注册包括网络地址作为注册的一部分。默认情况下,它使用的地址是“本地主机的 IP 地址,采用“dotted-quad”格式。在您的设置中,此地址是127.0.0.1。
When your Windows box contacts the registration service for the address of the remote object, it gets back 127.0.0.1. It then tries to contact the remote object at that address. That's why it's going to the loopback address.
当您的 Windows 设备联系注册服务以获取远程对象的地址时,它会返回127.0.0.1. 然后它尝试联系该地址的远程对象。这就是为什么它要去回环地址。
回答by user2462210
I suggest a solution based on customized RMISocketFactory.
我建议基于自定义 RMISocketFactory 的解决方案。
Like explained on Sun Site, you can provide your own SocketFactory : http://docs.oracle.com/javase/7/docs/technotes/guides/rmi/socketfactory/
就像在 Sun Site 上解释的那样,您可以提供自己的 SocketFactory :http: //docs.oracle.com/javase/7/docs/technotes/guides/rmi/socketfactory/
My solution use this mecanism for intercept client socket creation, and replace the host received (127.0.0.1) by the good IP, well known by the client.
我的解决方案使用此机制来拦截客户端套接字创建,并用客户端熟知的良好 IP 替换接收到的主机 (127.0.0.1)。
Th rest of the communication mechanism is still based on java rmi standards.
其余的通信机制仍然基于 java rmi 标准。
With this implementation, the exporter does not have to know it's own IP, which is sometimes no easy (multiple network interfaces ...)
通过这种实现,导出器不必知道自己的 IP,这有时并不容易(多个网络接口...)
Here are the tree classes, the Factory, the Server and the Client. The Hello class and interface are also uploaded to be exhaustive.
这里是树类、工厂、服务器和客户端。还上传了 Hello 类和接口以详尽无遗。
Hope it should be utile
希望它应该有用
SocketFactory:
套接字工厂:
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;
}
}
Exporter :
出口商:
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);
}
}
Client :
客户 :
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"));
}
}
Bean :
豆角,扁豆 :
import java.io.Serializable;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Hello extends Remote, Serializable {
String hello(String mess) throws RemoteException;
}
Impl :
实施:
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;
}
}
last and least, java.policy :
最后也是最不重要的, java.policy :
grant {
permission java.security.AllPermission;
};

