我的客户端和服务器位于不同的计算机上。
当我尝试在客户端上反序列化对象时,我收到此异常。
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/product/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"+ 服务器上的项目根路径);
将提供具有远程代码库路径的 RMI。
例如,您可以通过调用 MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath()
来获取服务器上的根路径。
不过你应该小心。这样任何人都可以访问您服务器计算机上的任何文件。明智的做法是在句柄中写入一些安全条件或修改策略文件。
最佳答案
问题在于,在客户端上,您指定了一个 file:
URI,它告诉 JVM 在本地文件系统中查找类。当您在与服务器相同的实际机器上运行客户端 JVM 时,这是有效的,但是如果您希望客户端能够从不同的机器下载类,则必须为其提供某种可以通过以下方式访问的 URI网络。您可以使用已安装的网络共享来执行此操作,但标准方法是通过 HTTP 提供 jar(或裸类文件)。 Oracle tech notes on dynamic code downloading有详尽的解释和几个例子。
如果您希望 RMI 服务器能够“独立”运行而不与任何其他服务通信,您可以在其中嵌入一个绑定(bind)到随机端口的 Web 服务器,然后为客户端提供一个 RMI 方法从服务器检索 URI 进行下载。
关于java.rmi.UnmarshalException : java. lang.ClassNotFoundException。无法使用 RMI 从另一个物理 JVM 访问类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19886814/