【问题标题】:"java.rmi.ConnectException: Connection refused to host" when exporting an object client-side导出对象客户端时出现“java.rmi.ConnectException: Connection refused to host”
【发布时间】:2013-03-26 22:36:13
【问题描述】:

我已经坚持了至少 5 个小时,除了在这里问之外别无他法。我正在编写一个 RMI 应用程序。我希望服务器绑定一个远程对象(此处为NoteBoardImpl),客户端将查找该对象。客户端将其监听器(此处为NoteBoardListener)传递给服务器,监听器也是客户端导出的远程对象。

我在这里准备了一个简单的SSCCE,所以我真的希望有人可以研究一下。所有类都在默认包的同一个文件夹中。我知道这是不鼓励的,我应该将应用程序分成三个罐子,但我想在这里尽可能简单。

远程接口:

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface INoteBoard extends Remote {
    public void test(INoteBoardListener listener) throws RemoteException;
}


import java.rmi.Remote;
import java.rmi.RemoteException;

public interface INoteBoardListener extends Remote {
    public void onNewText(String text) throws RemoteException;
}

接口实现:

import java.rmi.RemoteException;

public class NoteBoardImpl implements INoteBoard {
    @Override
    public void test(INoteBoardListener listener) throws RemoteException {
        listener.onNewText("server call the listener");
    }
}


import java.rmi.RemoteException;

public class NoteBoardListener implements INoteBoardListener {
    @Override
    public void onNewText(String text) throws RemoteException {
        System.out.println(text);
    }
}

客户端和服务器:

import java.rmi.Naming;
import java.rmi.server.UnicastRemoteObject;

public class Client {
    public static void main(String[] args) {
        if (args.length < 2) {
            System.out.println("2 arguments required:\nRMI_IP RMI_port");
            return;
        }
        System.setProperty("java.rmi.server.hostname", args[0]);
        try {
            INoteBoard nb = (INoteBoard) Naming.lookup(String.format("rmi://%s:%s/note", args[0], args[1]));
            INoteBoardListener l = (INoteBoardListener) UnicastRemoteObject.exportObject(new NoteBoardListener(), 0);
            nb.test(l);
            l.onNewText("client invokes listener");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


import java.rmi.Naming;
import java.rmi.server.UnicastRemoteObject;

public class Server {
    public static void main(String[] args) {
        if (args.length < 2) {
            System.out.println("2 arguments required:\nRMI_IP RMI_port");
            return;
        }
        System.setProperty("java.rmi.server.hostname", args[0]);
        try {
            INoteBoard noteBoard = (INoteBoard) UnicastRemoteObject.exportObject(new NoteBoardImpl(), 0);
            Naming.rebind(String.format("rmi://%s:%s/note", args[0], args[1]), noteBoard);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

我尝试模拟分布式系统以进行测试,并在虚拟机上运行客户端。主机-虚拟机网络具有以下规格 - 主机 IP = 192.168.56.1,虚拟机 IP = 192.168.56.101。
首先,我使用以下命令在本地运行客户端和服务器(事先已启动 rmiregistry 1099)。工作目录是项目的根目录,编译后的类在bin目录:
java -cp bin -Djava.rmi.server.codebase=http://student.agh.edu.pl/~grajewsk/bin/ Server 192.168.56.1 1099
java -cp bin Client 192.168.56.1 1099
它奏效了。

然后我使用相同的命令在 VM 上运行客户端程序,这是我得到的异常:

java.rmi.ConnectException: Connection refused to host: 192.168.56.1; nested exception is: 
    java.net.ConnectException: Connection refused
    at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619)
    at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216)
    at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:128)
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
    at sun.proxy.$Proxy0.test(Unknown Source)
    at Client.main(Client.java:14)
Caused by: java.net.ConnectException: Connection refused
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:327)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:193)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:180)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:384)
    at java.net.Socket.connect(Socket.java:546)
    at java.net.Socket.connect(Socket.java:495)
    at java.net.Socket.<init>(Socket.java:392)
    at java.net.Socket.<init>(Socket.java:206)
    at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:40)
    at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:146)
    at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:613)
    ... 7 more

请注意如何在服务器的注册表中成功查找对象,然后导出客户端远程对象(也成功),并且执行在第 14 行中断,我正在尝试调用传递客户端对象的服务器端对象上的方法。

我在任何一个系统上都没有防火墙,两个方向的 ping 都完美无缺。我知道这里肯定存在一些概念问题,当然我误解了关于 RMI 的一些内容。非常感谢您的帮助。

二进制代码库是on my student's server,以及the source code。提前谢谢!

【问题讨论】:

  • 你能从 192.168.56.101 ping 192.168.56.1 吗?
  • 是的,正如我所写的“双向 ping 完美无缺”。此外,尽管我在机器上运行服务器,但我可以远程登录到 rmiregistry 和服务器端口,因此我可以在主机或 VM 上运行服务器,并且可以通过远程登录连接到另一台机器的端口。

标签: java jvm client-server virtual-machine rmi


【解决方案1】:

这就是我要做的事情。

  1. 运行您的服务器应用程序
  2. 找出它用于 RMI 的端口(它是短暂的,所以它应该随着您为服务器创建的每个进程而改变)。

    • 使用 ps -ef 查找 PID
    • 然后 netstat -anp|grep 这应该会给你端口号。并且应该绑定到 0.0.0.0
  3. 在客户端 VM 上,使用 nc 或 telnet 验证您可以连接到端口。如果失败,您可能遇到了防火墙/iptables 问题。

  4. 使用 wireshark 来验证您的客户端是否确实在尝试连接到您从第 2 步中学到的端口/IP 组合。

请记住,仅仅因为您可以 ping,并不意味着您可以连接到给定的端口。还要检查“iptables -L”。

另外,Naming 表示不要放置 URL 的方案组件。格式应该是//host:port/name,所以你也应该检查一下。

【讨论】:

  • 谢谢你的建议,其实我不知道有这么好的测试端口连通性的方法。无论如何,无论我是在主机上还是在虚拟机上运行服务器,这里的一切似乎都运行良好。我了解到我的一个朋友在虚拟机和主机之间运行这个问题,所以我明天会问他,希望能在这里发布解决方案。但我仍在等待你的建议,如果你能在这里发现一些明显的错误。
  • 如果你为你的虚拟机使用 NAT 连接,试试桥接连接。这可能只是你的问题,否则如果你想使用 NAT,你必须设置一个端口转发(使用 RMI 可能并不容易)。虽然这并不能解释为什么您可以从客户端连接到 RMIRegistry。
  • 我在 VirtualBox 中使用 Host-only 适配器。我不确定它是如何模拟网络的。我稍后会尝试桥接适配器。
【解决方案2】:

好的,终于解决了。问题是,我在两个程序中传递了相同的java.rmi.server.hostname 参数,这意味着客户端和服务器都在这里获得了服务器的地址。事实证明,如果客户端想要导出自己的对象,它必须向java.rmi.server.hostname 提供自己的 IP。这样一切正常。

所以,总而言之,我必须向服务器提供 3 个参数:
RMI_IP RMI_port server_hostname

以及 3 个与客户端类似的参数:
RMI_IP RMI_port 客户端主机名

【讨论】:

    猜你喜欢
    • 2023-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    • 2019-02-24
    • 2017-01-13
    • 2013-05-29
    • 2021-10-03
    相关资源
    最近更新 更多