異なるマシンにクライアントとサーバーがあります。
クライアントでオブジェクトを逆シリアル化しようとすると、この例外が発生します。
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がサーバークラスファイルにアクセスできないか、間違ったパスを使用していると思います。
msg.getMessage() はこれを返します: /C:/Projects/IDEA/KachNetworkLab/out/production/server/
どんな提案でも大歓迎です。
解決:
この HttpServer は私にとってはうまくいきました。多分他の誰かがこれが便利だと思うでしょう...
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();
クライアントで呼び出すSystem.setProperty("java.rmi.server.codebase", "http://" + IP + ":8000" + project root path on server);
と、RMI にリモート コードベース パスが提供されます。
MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath()
たとえば、を呼び出すことで、サーバー上のルートパスを取得できます 。
ただし、注意が必要です。このようにして、誰でもサーバー マシン上の任意のファイルにアクセスできます。ハンドルにいくつかのセキュリティ条件を書き込むか、ポリシー ファイルを変更することをお勧めします。