有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

客户端调用时java RMI服务器ClassNotFoundException

我正在尝试在本地机器上运行一个简单的RMI执行引擎,以便其他java程序可以轻松地在第二个处理器上运行代码。(在未来,这将扩展以允许更多处理器)

服务器正常启动,客户端似乎找到了注册表ok,但当它尝试调用执行引擎(并向其传递参数)时,会导致ClassNotFoundException

我认识到这与关于堆栈溢出的许多其他问题类似,但据我所知,所有其他问题都与客户端无法下载服务器的类有关,而不是与服务器无法下载客户端的类有关

这是我的代码(几乎完全是从this sample code复制的):

RMIServerEclipse项目

计算机引擎接口:

package interfaces;

import java.io.Serializable;
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface ComputeEngine_IF extends Remote {

    /**
    * @param task The task object specifying the computation to be performed
    * @return
    * @throws RemoteException
    */
    <T extends Serializable> T compute(TaskWithoutInput<T> task) throws RemoteException;
}

TaskWithOutput接口:

package interfaces;

import java.io.Serializable;

public interface TaskWithoutInput<T> extends Serializable {
    public T compute();
}

计算机引擎类:

package server;

import interfaces.ComputeEngine_IF;
import interfaces.TaskWithoutInput;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class ComputeEngine implements ComputeEngine_IF{

    public ComputeEngine() {
        super();
    }

    @Override
    public <T extends Serializable> T compute(TaskWithoutInput<T> task) throws RemoteException {
        return task.compute();
    }

    public static void main(String[] args) {
        if(System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }

        try {
            String name = "Compute";
            ComputeEngine_IF engine = new ComputeEngine();
            ComputeEngine_IF stub = (ComputeEngine_IF) UnicastRemoteObject.exportObject(engine, 0);
            Registry registry = LocateRegistry.createRegistry(1099);
            registry.rebind(name, stub);

            System.out.println("Registry bound!");

        }
        catch (Exception e) {
            System.err.println("ComputeEngine exception:");
            e.printStackTrace();
        }
    }
}

RMIClientEclipse项目

GetAnswerTask类

package client;

import interfaces.TaskWithoutInput;

public class GetAnswerTask implements TaskWithoutInput<Integer> {

    private static final long serialVersionUID = 1L;

    @Override
    public Integer compute() {
        return Integer.valueOf(42);
    }
}

客户端类

package client;

import interfaces.ComputeEngine_IF;
import interfaces.TaskWithoutInput;

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

public class RmiClientExample {


    public static void main(String args[]) {
        if(System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }

        try {

            String name = "Compute";
            Registry registry = LocateRegistry.getRegistry("localhost");
            ComputeEngine_IF comp = (ComputeEngine_IF) registry.lookup(name);
            TaskWithoutInput<Integer> getAnswer = new GetAnswerTask();

            Integer answer = comp.compute(getAnswer);
            System.out.println("Answer: " + answer);

        }
        catch (Exception e) {
            System.err.println("RmiClientExample exception:");
            e.printStackTrace();
        }
    }
}

两个项目都包含相同的安全策略文件(在RMIServer中称为server.policy,在RMIClient中称为client.policy)

grant  {
    permission java.security.AllPermission;
};

当然,我会在这项工作完成后再次限制权限

建筑/运行

由于代码与我从示例中复制的内容非常接近,我猜测代码是正确的,或者至少是接近的,但我的错误在于编译/运行代码。这个例子不是为eclipse编写的,所以我没有确切的说明

我做的第一件事是使用eclipse的jar导出向导将接口包jar到接口中。我刚刚放在RMIServer文件夹中的jar

然后,我使用以下定义运行ComputeEngine:

-Djava.rmi.server.codebase=file:/c:/Users/nate/workspace/RMIServer/Interfaces.jar
-Djava.rmi.server.hostname=localhost
-Djava.security.policy=c:/Users/nate/workspace/RMIServer/src/server.policy

计算引擎似乎只运行find并在代码中输出print语句

然后,我使用以下定义运行客户端:

-Djava.rmi.server.codebase=file:/c:/Users/nate/workspace/RMIClient/bin/
-Djava.security.policy=c:/Users/nate/workspace/RMIClient/src/client.policy

我得到以下错误消息:

RmiClientExample exception:
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: client.GetAnswerTask
    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 java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
    at com.sun.proxy.$Proxy0.compute(Unknown Source)
    at client.RmiClientExample.main(RmiClientExample.java:24)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: client.GetAnswerTask
    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)
Caused by: java.lang.ClassNotFoundException: client.GetAnswerTask
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.rmi.server.LoaderHandler$Loader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at sun.rmi.server.LoaderHandler.loadClassForName(Unknown Source)
    at sun.rmi.server.LoaderHandler.loadClass(Unknown Source)
    at sun.rmi.server.LoaderHandler.loadClass(Unknown Source)
    at java.rmi.server.RMIClassLoader$2.loadClass(Unknown Source)
    at java.rmi.server.RMIClassLoader.loadClass(Unknown Source)
    at sun.rmi.server.MarshalInputStream.resolveClass(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(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.server.UnicastRef.unmarshalValue(Unknown Source)
    at sun.rmi.server.UnicastServerRef.unmarshalParametersUnchecked(Unknown Source)
    at sun.rmi.server.UnicastServerRef.unmarshalParameters(Unknown Source)
    ... 13 more

有没有想过我可能做错了什么


共 (2) 个答案

  1. # 1 楼答案

    GetAnswerTask实现了Serializable,因此当您调用ComputeEngine_IF.compute()时,它将被序列化到服务器。所以GetAnswerTask需要在服务器上、在其类路径上可用,而不是

  2. # 2 楼答案

    对于那些仍在努力学习oracle RMI教程的人,他们的服务器不从给定客户机的代码库下载可序列化类(并且顽固地在自己的代码库中寻找类),请尝试添加

    -Djava.rmi.server.useCodebaseOnly=false
    

    到服务器的参数