Я пытаюсь создать простой механизм выполнения RMI для запуска на моем локальном компьютере, чтобы другие java-программы могли легко запускать код на втором процессоре. (В будущем это будет расширено, чтобы позволить больше процессоров).RMI server ClassNotFoundException, когда клиент делает вызов
Сервер запускается очень хорошо, и клиент, похоже, находит реестр в порядке, но когда он пытается вызвать механизм выполнения (и передает его параметр), он вызывает исключение ClassNotFoundException.
Я признаю, что это похоже на многие другие вопросы о переполнении стека, но, насколько я могу судить, все остальные связаны с тем, что клиент не может загружать классы сервера, а не сервер, не являющийся способный загружать классы клиента.
Вот мой код (скопировано почти точно с this sample code):
RMIServer затмение проект
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();
}
}
}
RMIClient затмение проект
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);
}
}
класс Client
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, поэтому у меня нет точных инструкций.
Первое, что я сделал, это использовать мастер экспорта jar eclipse для создания пакета интерфейса в интерфейсе Interface.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
вычислитель, кажется, бежит просто найти и выводит оператор печати в коде.
Я затем запустить клиент с устанавливает:
-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
Любые мысли о том, что я могу делать неправильно?
Мое понимание, основанное на этом [учебнике] (http://docs.oracle.com/javase/tutorial/rmi/overview.html), состояло в том, что, помещая определения классов в общедоступное место и устанавливая java.rmi .server.codebase для URL-адреса в этом месте, сервер может затем получить определения класса без необходимости иметь классы в своем пути к классам. Вся идея моего вычислительного механизма RMI - позволить серверу выполнять код, который не находится в его пути к классам, чтобы любое другое приложение Java могло запускать свой код на этом общем процессоре. – NateW
PS. Я попытался удалить интерфейс Serializable из TaskWithoutInput, чтобы убедиться, что это имеет значение. Теперь я получаю «java.rmi.MarshalException: аргументы marshalling ошибки; вложенное исключение: \t java.io.NotSerializableException: client.GetAnswerTask», что интересно, поскольку в учебнике я не думаю, что они когда-либо использовали интерфейс Serializable. В этом руководстве рассказывается о сериализации, но я не думаю, что это вообще отображается в примере кода. – NateW
Так вы удовлетворили условия? Является ли свойство 'java.rmi.server.codebase' установленным на клиенте? Указывает ли оно на местоположение, доступное под этим именем сервером? Вы проверили это? Предоставляет ли политика безопасности вашего сервера доступ к серверу кода? Вы изучили серверные журналы для поставщика кодовой базы, чтобы узнать, что на самом деле происходит? NB Удаление «Serializable» из класса, который в нем нуждается, был пустой тратой времени. Я не знаю, почему ты беспокоился. В учебнике ['Pi' class] (http://docs.oracle.com/javase/tutorial/rmi/client.html) реализовано' Serializable'. – EJP