Java RMI 问题:无法解决线程中的异常 "main" java.rmi.NotBoundException:服务器

Java RMI issue: Can't solve Exception in thread "main" java.rmi.NotBoundException: Server

我收到以下错误:

Exception in thread "main" java.rmi.NotBoundException: Server
at java.rmi/sun.rmi.registry.RegistryImpl.lookup(RegistryImpl.java:234)
at java.rmi/sun.rmi.registry.RegistryImpl_Skel.dispatch(RegistryImpl_Skel.java:133)
at java.rmi/sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:468)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:298)
at java.rmi/sun.rmi.transport.Transport.run(Transport.java:200)
at java.rmi/sun.rmi.transport.Transport.run(Transport.java:197)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run[=13=](TCPTransport.java:677)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
at java.rmi/sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:303)
at java.rmi/sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:279)
at java.rmi/sun.rmi.server.UnicastRef.invoke(UnicastRef.java:380)
at java.rmi/sun.rmi.registry.RegistryImpl_Stub.lookup(RegistryImpl_Stub.java:123)
at client.RMIClient.startClient(RMIClient.java:17)
at client.FahrradClient.main(FahrradClient.java:12)

谁能看看我的代码并告诉我哪里出错了?我将不胜感激。甚至会发送小费或其他东西 lmao 我很绝望。

package server;
import shared.RMI_Interface;

import java.io.IOException;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class FahrradServer {
    public static void main(String[] args) throws IOException, AlreadyBoundException {
        RMI_Interface server = new ConfigImpl();
        Registry registry = LocateRegistry.createRegistry(1099);
        Runtime.getRuntime().exec("rmiregistry 1099");
        registry.bind("Server", server);
        System.out.println("Server started");
    }
}

package client;
import shared.Fahrrad;
import shared.RMI_Interface;

import java.rmi.*;
import java.rmi.registry.*;

public class RMIClient {
    private RMI_Interface server;

    public RMIClient() {}

    public void startClient() throws RemoteException, NotBoundException {
        Registry registry = LocateRegistry.getRegistry("localhost", 1099);
        server = (RMI_Interface)registry.lookup("Server");
    }

    public Fahrrad configureFahrrad(String lenkertyp,  String material, String schaltung, String griff ) {
        Fahrrad result = null;
        try {
            result = server.configureFahrrad(lenkertyp, material, schaltung, griff);
        } catch (RemoteException e) {
            e.printStackTrace();
            throw new RuntimeException("Could not contact server");
        }
        return result;
    }
}

package server;

import shared.Fahrrad;
import shared.RMI_Interface;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class ConfigImpl implements RMI_Interface {

    public void ConfigImpl() throws RemoteException {
        UnicastRemoteObject.exportObject(this, 0);
    }

    @Override
    public Fahrrad configureFahrrad(String lenkertyp,  String material, String schaltung, String griff ) throws RemoteException {
        Fahrrad f = new Fahrrad();
        f.setLenkertyp(lenkertyp);
        f.setGriff(griff);
        f.setMaterial(material);
        f.setSchaltung(schaltung);

        if (!lenkertyp.equals( "Faltbarlenker")  && !lenkertyp.equals( "Rennradlenker") && !lenkertyp.equals( "Bullhornlenker")) {
            throw new IllegalArgumentException("Ungültiger Lenktypinput");
        }

        if (!material.equals( "Aluminium") && !material.equals( "Stahl") && !material.equals( "Kunststoff")){
            throw new IllegalArgumentException("Ungültiges Material!");
        }

        if (!schaltung.equals("Kettenschaltung") && !schaltung.equals( "Tretlagerschaltung") && !lenkertyp.equals( "Nebenschaltung")) {
            throw new IllegalArgumentException("Ungültige Schaltung!");
        }

        if (!griff.equals( "Kunststoffgriff") && !griff.equals( "Ledergriff") && !lenkertyp.equals( "Schaumstoffgriff")) {
            throw new IllegalArgumentException("Ungültige Schaltung!");
        }

        if (lenkertyp.equals("Faltbarlenker") || lenkertyp.equals("Rennradlenker")) {
            if (!material.equals( "Aluminium") && !material.equals( "Kunststoff")) {
                throw new IllegalArgumentException(lenkertyp + " kann nur aus Aluminium oder Kunststoff bestehen.");
            }
        }

        if (material.equals("Stahl")) {
            if (!schaltung.equals("Kettenschaltung")) {
                throw new IllegalArgumentException("Materialtyp "+ material + " kann nur Kettenschaltung haben!");
            }
        }

        if (material.equals("Kunststoff")) {
            if (griff.equals("Kunststoffgriff")) {
                throw new IllegalArgumentException("Nur Kunststoffmaterial kann Kunststoffgriff haben!");
            }
        }

        if (lenkertyp.equals( "Bullhornlenker") || lenkertyp.equals("Faltbarlenker")) {
            if (griff.equals("Ledergriff")) {
                throw new IllegalArgumentException("Nur Rennladlenker können Ledergriffe haben!");
            }
        }
        return f;
    }
}

package server;
import shared.RMI_Interface;

import java.io.IOException;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class FahrradServer{
    public static void main(String[] args) throws IOException, AlreadyBoundException {
        RMI_Interface server = new ConfigImpl();
        Registry registry = LocateRegistry.createRegistry(1099);
        Runtime.getRuntime().exec("rmiregistry 1099");
        registry.bind("Server", server);
        System.out.println("Server started");
    }
}

package shared;

public class Fahrrad {
    public String lenkertyp;
    public String material;
    public String schaltung;
    public String griff;

    public void setLenkertyp(String lenkertyp){
        this.lenkertyp=lenkertyp;
    }

    public String getLenkertyp() {
        return lenkertyp;
    }

    public void setMaterial(String material){
        this.material=material;
    }

    public String getMaterial() {
        return material;
    }

    public void setSchaltung(String schaltung) {
        this.schaltung=schaltung;
    }

    public String getSchaltung() {
        return schaltung;
    }

    public void setGriff(String griff){
        this.griff=griff;
    }

    public String getGriff() {
        return griff;
    }
}

package shared;

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

// Creating Remote interface for our application
public interface RMI_Interface extends Remote {
    public Fahrrad configureFahrrad(String lenkertyp,  String material, String schaltung, String griff ) throws RemoteException;
}

我知道代码并不完美。我会改变它,但最重要的是让客户端和服务器独立 运行。遗憾的是,我的客户没有 运行.

创建 RMI 应用程序时要遵循的步骤。

  1. 创建“远程”界面。
    您的界面 RMI_Interface 没问题。此处无事可做。
  2. 创建一个实现远程接口的class。
    我让构造函数为空。 (其余代码不变。)
public ConfigImpl() throws RemoteException {
    // Empty.
}
  1. 创建 RMI 服务器。这里我做了一些改动。
package server;

import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import shared.RMI_Interface;

public class FahrradServer {

    public static void main(String[] args) {
        try {
            ConfigImpl server = new ConfigImpl();
            RMI_Interface stub = (RMI_Interface) UnicastRemoteObject.exportObject(server, 0);
            Registry registry = LocateRegistry.createRegistry(1099);
            registry.bind("Server", stub);
            System.out.println("Server started");
        }
        catch (AlreadyBoundException | RemoteException x) {
            x.printStackTrace();
        }
    }
}

请注意,调用方法 createRegistry() 将启动 rmiregistry,因此不需要这行代码:

Runtime.getRuntime().exec("rmiregistry 1099");
  1. 运行 服务器,即 java server.FahrradServer
    (我假设您知道实际启动服务器所需的正确命令。)
    请注意,服务器程序将永远运行——除非你杀死它。
  2. 写客户端。客户端将 运行 在单独的 JVM 中,因此客户端需要一个 main() 方法,以便您可以通过 java 命令启动它。
package client;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import shared.Fahrrad;
import shared.RMI_Interface;

public class RMIClient {
    private RMI_Interface server;

    public void startClient() throws RemoteException, NotBoundException {
        Registry registry = LocateRegistry.getRegistry(1099);
        server = (RMI_Interface) registry.lookup("Server");
    }

    public Fahrrad configureFahrrad(String lenkertyp,
                                    String material,
                                    String schaltung,
                                    String griff) throws RemoteException {
        return server.configureFahrrad(lenkertyp, material, schaltung, griff);
    }

    public static void main(String[] args) {
        RMIClient client = new RMIClient();
        try {
            client.startClient();
            Fahrrad f = client.configureFahrrad("Faltbarlenker",
                                                "Aluminium",
                                                "Kettenschaltung",
                                                "Kunststoffgriff");
            System.out.println("Fahrrad: " + f);
        }
        catch (RemoteException | NotBoundException x) {
            x.printStackTrace();
        }
    }
}
  1. 由于远程接口方法的return值是你写的class,那class必须实现接口Serializable,即
public class Fahrrad implements java.io.Serializable
  1. 现在您可以启动 RMI 客户端,例如java client.RMIClient

参考 Oracle java 教程的 RMI 线索。