尝试将远程对象绑定到 RMI 注册表时的 IllegalArgumentException



我已经编写了一个简单的 RMI 应用程序,但我无法将我的远程对象绑定到 RMI 注册表。RMI 注册表正在从单独的 cmd 窗口运行 [我在 Windows 10 上]。远程界面非常简单:

package matram;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteInterface extends Remote {
    public String sayHello() throws RemoteException;
}

实现也很简单:

package matram;
import java.rmi.RemoteException;
public class Test1 extends java.rmi.server.UnicastRemoteObject implements RemoteInterface {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public Test1() throws RemoteException {
        super();
    }
    @Override
    public String sayHello() throws RemoteException {
        { return "Hello world!"; }
    }
}

这是服务器,其中包含 main 方法:

package matram;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.Naming;
public class RemoteDCmain {
    public static Test1 dc;
    public static void main(String[] args) throws InterruptedException {
        if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); }
        try {
            String name = "DCregistry";
            dc = new Test1();
            Naming.rebind(name, dc);
            print("dc bound");
        }
        catch (java.rmi.RemoteException ex) {
            print("Remote Exception");
            ex.printStackTrace();;
        }
        catch (Exception e) {
            print("Naming.rebind exception:");
            e.printStackTrace();
        }
        try {
            final InetAddress localaddr = InetAddress.getLocalHost();
            print("Local IP Address : " + localaddr);
        } catch (UnknownHostException e) {
            print("Can't detect localhost : " + e);
        }
        init();
    } // main
    private static void init() {
        try {
        //  (new Thread((Runnable) dc)).start();
            Thread.sleep(1200);
        } catch (Exception e) {
            print(String.format("Could not connect to account W"));
            e.printStackTrace();
        }
    } // init()
    public static void print(Object o) {
        System.out.println("DC server: " + o);
    }
}

当我[从Eclipse中]运行它时,我得到

DC server: Naming.rebind exception:java.lang.IllegalArgumentException
    at sun.net.www.ParseUtil.decode(Unknown Source)
    at sun.net.www.protocol.file.Handler.openConnection(Unknown Source)
    at sun.net.www.protocol.file.Handler.openConnection(Unknown Source)
    at java.net.URL.openConnection(Unknown Source)
    at sun.rmi.server.LoaderHandler.addPermissionsForURLs(Unknown Source)
    at sun.rmi.server.LoaderHandler.getLoaderAccessControlContext(Unknown Source)
    at sun.rmi.server.LoaderHandler.lookupLoader(Unknown Source)
    at sun.rmi.server.LoaderHandler.loadProxyClass(Unknown Source)
    at java.rmi.server.RMIClassLoader$2.loadProxyClass(Unknown Source)
    at java.rmi.server.RMIClassLoader.loadProxyClass(Unknown Source)
    at sun.rmi.server.MarshalInputStream.resolveProxyClass(Unknown Source)
    at java.io.ObjectInputStream.readProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.oldDispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
    at sun.rmi.server.UnicastRef.invoke(Unknown Source)
    at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
    at java.rmi.Naming.rebind(Unknown Source)
    at matram.RemoteDCmain.main(RemoteDCmain.java:16)

我真的不知道这是从哪里来的。而且我什至还没有调用客户端...

at sun.net.www.protocol.file.Handler.openConnection(Unknown Source)

您在某处使用file: URL。

  at sun.rmi.server.LoaderHandler.lookupLoader(Unknown Source)

您正在使用类装入器。

结论:您在java.rmi.serve.codebase系统属性中指定了无效的 file: URL。

我还会问你为什么使用file: URL。除非客户端位于同一主机上,否则它对客户端没有任何用处,在这种情况下,您实际上根本不需要代码库功能。

为了更好地练习Java中的集成组件,要记住的一件事是使用CMD。我并不是因为使用日食而劝阻你,但RMI是一个不同的情况。在Java RMI中,你需要使用命令rmiregistry 4545显式地在某个自由端口(比如4545)上启动RMI注册表,你还需要编译服务器类,而不是用javac而是用rmic。最后一件事;对 RMI 服务器地址使用完全限定的 URL。例如 : rmic://localhost:4545/myServer

最新更新