2016-06-14 8 views
0

Я пытаюсь создать простой механизм выполнения 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 

Любые мысли о том, что я могу делать неправильно?

ответ

0

GetAnswerTask реализует Serializable, поэтому он будет сериализован на сервер при вызове ComputeEngine_IF.compute(). Таким образом, GetAnswerTask должен быть доступен на сервере, на его пути к классам, и это не так.

+0

Мое понимание, основанное на этом [учебнике] (http://docs.oracle.com/javase/tutorial/rmi/overview.html), состояло в том, что, помещая определения классов в общедоступное место и устанавливая java.rmi .server.codebase для URL-адреса в этом месте, сервер может затем получить определения класса без необходимости иметь классы в своем пути к классам. Вся идея моего вычислительного механизма RMI - позволить серверу выполнять код, который не находится в его пути к классам, чтобы любое другое приложение Java могло запускать свой код на этом общем процессоре. – NateW

+0

PS. Я попытался удалить интерфейс Serializable из TaskWithoutInput, чтобы убедиться, что это имеет значение. Теперь я получаю «java.rmi.MarshalException: аргументы marshalling ошибки; вложенное исключение: \t java.io.NotSerializableException: client.GetAnswerTask», что интересно, поскольку в учебнике я не думаю, что они когда-либо использовали интерфейс Serializable. В этом руководстве рассказывается о сериализации, но я не думаю, что это вообще отображается в примере кода. – NateW

+0

Так вы удовлетворили условия? Является ли свойство 'java.rmi.server.codebase' установленным на клиенте? Указывает ли оно на местоположение, доступное под этим именем сервером? Вы проверили это? Предоставляет ли политика безопасности вашего сервера доступ к серверу кода? Вы изучили серверные журналы для поставщика кодовой базы, чтобы узнать, что на самом деле происходит? NB Удаление «Serializable» из класса, который в нем нуждается, был пустой тратой времени. Я не знаю, почему ты беспокоился. В учебнике ['Pi' class] (http://docs.oracle.com/javase/tutorial/rmi/client.html) реализовано' Serializable'. – EJP