2013-11-10 2 views
0

다른 컴퓨터에 클라이언트와 서버가 있습니다.java.rmi.UnmarshalException : java.lang.ClassNotFoundException. RMI를 사용하여 다른 실제 JVM에서 클래스에 액세스 할 수 없음

클라이언트에서 개체를 deserialize하려고 할 때이 예외가 발생합니다.

java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
java.lang.ClassNotFoundException: task.MyTask 

여기 내 서버 코드입니다 :

System.setProperty("java.security.policy", "all_policy.policy"); 
System.setSecurityManager(new RMISecurityManager()); 
     try 
     { 
      mngr = new Manager(); 
      registry = LocateRegistry.createRegistry(15120); 

      TaskDistributor stub = (TaskDistributor) UnicastRemoteObject.exportObject(mngr, 0); 
      registry.rebind("Manager", stub); 
     } 
catch (Exception e) 
     { 
      System.out.println ("Ошибка при инициалиазации RMI: " + e.getMessage() + "\n"); 
      e.printStackTrace(); 
     } 
... 

try 
    { 
     //when creating a new task 
     mngr.setTask(task); 
    } 
    catch (Exception e) 
    { 
     System.out.println ("Ошибка при передаче задания: " + e.getMessage() + "\n"); 
     e.printStackTrace(); 
    } 

그리고 여기 클라이언트 : 내가 같은 로컬 컴퓨터에서 사용할 경우

try 
{ 
    //msg.getMessage() = MyTask.class.getClassLoader().getResource("").getPath() called on server machine 
    System.setProperty("java.rmi.server.codebase", "file://" + server + msg.getMessage()); 
    Registry registry = LocateRegistry.getRegistry(server, 15120); 
    TaskDistributor mngr = (TaskDistributor) registry.lookup("Manager"); 
    cg.append("Задание получено\n"); 

    MatrixMultiplier task = mngr.getTask(); //<------------Exception here 
    task.multiply(); 

    mngr.setTask(task); 

    client.sendMessage(new ChatMessage(ChatMessage.TASK_COMPLETED, "")); 
} 
catch (Exception e) 
{ 
    System.out.println ("Ошибка: " + e.getMessage()); 
    e.printStackTrace(); 
} 

그것은 작업 그래서 난 생각합니까 JVM이 할 수있는 원격 클라이언트 서버 클래스 파일에 액세스 할 수 없거나 잘못된 경로를 사용하고 있습니다./C :

msg.getMessage()이를 반환/프로젝트/IDEA/KachNetworkLab/출력/생산/서버/

어떤 제안이 많이 주시면 감사하겠습니다.

솔루션 :이 HttpServer에 나를 위해 일한

. 어쩌면 다른 사람이 원격 코드베이스 경로 RMI를 제공 할 것입니다 클라이언트 System.setProperty("java.rmi.server.codebase", "http://" + IP + ":8000" + project root path on server);를 호출 ...이 유용

HttpServer httpServer = HttpServer.create(address, 10); 
httpServer.createContext("/", new HttpHandler() { 
      @Override 
      public void handle(HttpExchange t) throws IOException { 
       try { 
       File f = new File(t.getRequestURI().toString().substring(1).replace("\\", "/")); 
        System.out.println(t.getRequestURI().toString().substring(1).replace("\\", "/")); 
        if (!f.exists()) 
        { 
         StringBuilder response = new StringBuilder().append("No luck :("); 
         t.sendResponseHeaders(HttpURLConnection.HTTP_OK, response.toString().getBytes().length); 
         t.getResponseBody().write(response.toString().getBytes()); 
         t.getResponseBody().close(); 
         t.close(); 
         return; 
        } 

        t.sendResponseHeaders(HttpURLConnection.HTTP_OK, f.length()); 
        InputStream file = new FileInputStream(f); 
        sendFile(file, t.getResponseBody()); 
        t.getResponseBody().close(); 
        t.close(); 
       } 
       catch(Exception e) 
       { 
        e.printStackTrace(); 
       } 
      } 
     }); 

     httpServer.setExecutor(null); 
     httpServer.start(); 

을 찾을 수 있습니다.

예를 들어 MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath()을 호출하여 서버에서 루트 경로를 가져올 수 있습니다.

그래도 조심해야합니다. 이렇게하면 누구든지 서버 컴퓨터의 모든 파일에 액세스 할 수 있습니다. 핸들에 보안 조건을 쓰거나 정책 파일을 수정하는 것이 좋습니다.

답변

2

문제는 클라이언트에서 로컬 파일 시스템에서 클래스를 찾도록 JVM에 알려주는 file: URI를 지정하는 것입니다. 이 기능은 서버와 동일한 실제 컴퓨터에서 클라이언트 JVM을 실행할 때 작동하지만 클라이언트가 다른 컴퓨터에서 클래스를 다운로드 할 수있게하려면 액세스 할 수있는 일종의 URI를 제공해야합니다 네트워크. 마운트 된 네트워크 공유를 사용하여이를 수행 할 수 있지만 표준 방법은 HTTP를 통해 jar (또는 베어 클래스 파일)를 사용할 수있게 만드는 것입니다. Oracle tech notes on dynamic code downloading에는 철저한 설명과 몇 가지 예가 나와 있습니다.

다른 서비스와 통신하지 않고 RMI 서버가 "독립 실행 형"으로 실행되도록하려면 임의의 포트에 바인딩하는 웹 서버를 포함시킨 다음 해당 서버에 대한 RMI 방법을 사용할 수 있습니다 클라이언트는 다운로드를 위해 서버에서 URI를 검색합니다.

+0

이 프로젝트에서 RMI를 사용한 전체 점은 클라이언트가 로컬 코드베이스에'task.MyTask' 클래스가 없으므로'RMIClassLoader'를 사용하여 서버에서 다운로드하는 것입니다. – Sknictik

+0

@Sknictik 좋아요, 당신이 지금하려는 일을 이해하고 있다고 생각합니다. 다시 쓰기. – chrylis