我正在尝试在我的本地计算机上运行一个简单的RMI执行引擎,以便其他java程序可以在第二个处理器上轻松运行代码。 (将来会扩展到允许更多处理器)。
服务器启动很好,客户端似乎找到了注册表ok,但是当它试图调用执行引擎(并传递一个参数)时,它会导致ClassNotFoundException。
我认识到这与堆栈溢出上的许多其他问题类似,但据我所知,所有其他问题都与客户端无法下载服务器类而不是服务器无法运行下载客户的课程。
这是我的代码(几乎完全从this sample code复制):
ComputeEngine界面:
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;
}
TaskWithoutInput接口:
package interfaces;
import java.io.Serializable;
public interface TaskWithoutInput<T> extends Serializable {
public T compute();
}
ComputeEngine类:
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();
}
}
}
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导出向导将接口包装到Interfaces.jar中,我刚放在我的RMIServer文件夹中。
然后我使用以下定义运行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
计算引擎似乎只是在代码中运行查找并输出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
对我可能做错了什么的想法?
答案 0 :(得分:0)
GetAnswerTask
实现了Serializable,因此当您调用ComputeEngine_IF.compute()
时,它将被序列化到服务器。因此,GetAnswerTask
需要在服务器上,在其类路径上可用,并且它不是。
答案 1 :(得分:0)
对于那些仍在努力学习oracle RMI教程的人来说,他们的服务器并没有从给定客户端的代码库下载可序列化的类(并且固执地在自己的代码库中寻找类) - 尝试添加
-Djava.rmi.server.useCodebaseOnly=false
到服务器参数