无法使用RMI远程方法

时间:2017-02-12 19:25:28

标签: java rmi

无法解决这个问题3天。 RMI在1或2台PC上与localhost或192.168。*一起正常工作,但远程客户端无法使用远程方法。 启动rmiregisry,然后使用Naming.rebind()

绑定服务

注册表正在成功创建,我可以获得绑定服务列表,但我甚至无法使用任何方法。

使用

搜索远程服务
Naming.lookup("rmi://host_ip:1099/qwe). 
or
Registry reg = LocateRegistry.getRegistry("host_ip",server);
reg.lookup("qwe")

客户找到对象,但无法使用它的方法。

这是代码: Server.java:

public class Server extends UnicastRemoteObject{

protected Server() throws RemoteException {
}

public static void main(String[] args) throws InterruptedException, RemoteException {
    ServiceServerImpl server = new ServiceServerImpl();
    try {
        System.setProperty("java.rmi.server.hostname", "host_ip");
        Naming.rebind("/qwe", server);
        Arrays.asList(Naming.list("rmi://localhost")).forEach(System.out::println);
        System.out.println(System.getProperty("java.rmi.server.hostname"));
    } catch (Exception e) {
        e.printStackTrace();
    }
    server.startServer();
}
}

ServiceServer.java:

public interface ServiceServer extends Remote{
String[] getLoginsList() throws RemoteException;
void addLogin(String login) throws RemoteException;
void removeLogin(String login) throws RemoteException;
boolean canConnect(String login) throws RemoteException;
void setConnected(String login) throws RemoteException;
void setDisconnected(String login) throws RemoteException;
}

ServiceServerImpl.java(如果需要):

public class ServiceServerImpl extends UnicastRemoteObject implements ServiceServer {
private ServerSocket socketListener;
private Socket clientSock;
private volatile List<ClientHandler> threadsList = new ArrayList<ClientHandler>();
private volatile Map<String, Boolean> logins = new HashMap<String,Boolean>();
// private Timer timer;

public ServiceServerImpl() throws RemoteException {
}

public void startServer() {
    // startTimer();
    try {
        socketListener = new ServerSocket(5001);
        System.out.println("server up...");
        while (true) {
            clientSock = null;
            while (clientSock == null)
                clientSock = socketListener.accept();
            ClientHandler curClientHandler = new ClientHandler(clientSock, this);
            threadsList.add(curClientHandler);
            System.out.println("user connected: " + clientSock.getInetAddress());
        }
    } catch (Exception e) {
        System.err.println("Socket exception");
        e.printStackTrace();
    }
}

public synchronized void removeUserThread(ClientHandler handler) {
    try {
        threadsList.remove(handler);
    } catch (NullPointerException e) {
    }
    System.out.println("- 1");
}

@Override
public void setConnected(String login){
    logins.put(login,true);
}

@Override
public void setDisconnected(String login){
    logins.put(login,false);
}

@Override
public boolean canConnect(String login) throws RemoteException{
    return logins.keySet().contains(login)&& (!logins.get(login));
}

@Override
public String[] getLoginsList() throws RemoteException {
    return this.logins.keySet().toArray(new String[this.logins.size()]);
}

@Override
public void addLogin(String login) throws RemoteException {
    logins.put(login, false);
    System.out.println("added");
}

@Override
public void removeLogin(String login) throws RemoteException {
    logins.remove(login);
}


public Map<String, Boolean> getLogins() {
    return logins;
}

public Set<String> getAllowedLogins() {
    return logins.keySet();
}

public List<ClientHandler> getThreadsList() {
    return threadsList;
}
}

我用cmd或eclipse启动rmiregistry,然后启动Sever。 它正确启动,我无法连接localhost或192.168.0。* 但它没有为远程客户工作 试图使用.policy文件 - 仍然无法正常工作

我得到下一个错误代码:

Exception in thread "main" java.rmi.ConnectException: Connection refused to host: 192.168.0.83; nested exception is: 
java.net.ConnectException: Connection timed out: connect
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
at sun.rmi.server.UnicastRef.invoke(Unknown Source)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
at com.sun.proxy.$Proxy0.canConnect(Unknown Source)
at server.Main.main(Main.java:16)
Caused by: java.net.ConnectException: Connection timed out: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(Unknown Source)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(Unknown Source)
... 8 more

请帮助

3 个答案:

答案 0 :(得分:1)

你需要:

  1. java.rmi.server.hostname设置为系统的外部 IP地址,即路由器的公共IP地址。
  2. 通过super(port)
  3. 将固定端口号上的远程对象导出
  4. 在路由器中为这些端口和端口1099安排端口转发。
  5. 如何做(3)取决于路由器和非主题。

答案 1 :(得分:0)

根据您的描述,您遇到了一般网络连接问题,该问题并非特定于RMI。我的建议是抛开RMI并使用netcat或其他一些通用的客户端/服务器实现,直到你得到整理的连接内容,然后回到RMI。

我的猜测是,您必须至少有两层安全性。一个是运行RMI服务器的PC阻塞所有端口上的连接,或者只是一小部分端口阻塞连接。您首先需要在RMI主机上打开端口1099(这是默认的RMI端口,当然您可以选择其他东西)。如果这样做,您应该能够从同一本地网络上的另一台主机(即在同一子网192.168.something.something上)连接到RMI主机。

如果您的连接正常工作,那么下一个交叉的桥接器就是本地网络上的路由器可能阻止来自本地网络外部的流量。请记住,这是一项重要的安全措施。我的建议是避免从外部直接打开与RMI主机的连接,因为这是一个安全风险。而是尝试设置SSH隧道,然后使用隧道从外部传输到RMI主机的连接。 SSH隧道并不太复杂;网络搜索应该出现一个解释。

客户端也可能阻止到端口1099的出站连接;您必须启用这些连接,或使用SSH隧道来避免此问题。

在早期(大约1999年),我建立了一个通过RMI进行通信的全球网络(大约4个站点)。当时网络安全没有任何障碍。因此,通过RMI进行远程通信当然是可能的,您只需通过防火墙即可。祝你好运,玩得开心。

答案 2 :(得分:0)

192.168.X.X是一个私有/ C类IP地址,用于标识本地网络上的计算机。要向其他人/互联网用户公开您的服务,您需要在路由器上配置端口转发。它还有助于使用免费的动态DNS服务,如NoIP,以确保您的计算机即使在重新启动后仍然可以访问(假设您的ISP几乎总是为您分配一个新的动态公共IP地址)。

完成整理后,请确保您没有将RMI服务器绑定到localhost127.0.0.1,而是绑定到0.0.0.0