导出客户端对象时出现“java.rmi.ConnectException:Connection拒绝托管”

我现在已经坚持了至少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();
        }
    }
}

我试图模拟分布式系统进行测试,并在虚拟机上运行客户端.主机VM网络具有以下规范 – 主机IP = 192.168.56.1,VM 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客户端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.谢谢你提前!

解决方法:

以下是我要做的事情.

>运行您的服务器应用程序
>找出它用于RMI的端口(它是短暂的,因此它应该为您创建服务器的每个进程进行更改).

>使用ps -ef查找PID
>然后netstat -anp | grep这应该给你端口号.它应该绑定到0.0.0.0

>在客户端VM上,使用nc或telnet验证您是否可以连接到该端口.如果失败,您可能遇到防火墙/ iptables问题.
>使用wireshark验证您的客户端实际上是否尝试连接到您从步骤2中学到的port / ip组合.

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

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

上一篇:POJ 1035 Spell checker 简单字符串匹配


下一篇:Server failed to start: java.rmi.server.ExportException: Listen failed on port: 0; nested exception