客户端上的Java RMI ClassNotFoundException

客户端上的Java RMI ClassNotFoundException,java,intellij-idea,rmi,classnotfoundexception,Java,Intellij Idea,Rmi,Classnotfoundexception,有好几个问题都是这个题目,但没有一个能帮我解决问题 我一直在尝试遵循以下教程: 我把所有东西都放在一个项目中,这让我发疯,所以我创建了3个独立的项目: 服务器->它有Main(驱动程序),类:ServerNode实现计算 客户端->它有Main(驱动程序),类:TestTask实现任务 共享->它有接口:任务和接口:计算 这个想法是。。。这两个应用程序都需要了解Interfaces任务(客户端发送到服务器的工作单元)和Compute(客户端用于向其发出命令的ServerNode接口) 服务器代

有好几个问题都是这个题目,但没有一个能帮我解决问题

我一直在尝试遵循以下教程:

我把所有东西都放在一个项目中,这让我发疯,所以我创建了3个独立的项目:

  • 服务器->它有Main(驱动程序),类:ServerNode实现计算
  • 客户端->它有Main(驱动程序),类:TestTask实现任务
  • 共享->它有接口:任务和接口:计算
  • 这个想法是。。。这两个应用程序都需要了解Interfaces任务(客户端发送到服务器的工作单元)和Compute(客户端用于向其发出命令的ServerNode接口)

    服务器代码:

    System.setProperty("java.security.policy","file:server.policy");
        System.out.println(System.getProperty("java.security.policy"));
    
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }
        int port = 1099;
        try {
            LocateRegistry.createRegistry(port);
            String name = "Compute"; // Name of the interface
            Compute engine = new ServerNode(); // Implementor of Compute interface, ComputeEngine
            Compute stub =
                    (Compute) UnicastRemoteObject.exportObject(engine, 0); // Create the stub the client will use
            Registry registry = LocateRegistry.getRegistry(port);
            registry.bind(name, stub);   // Bind the "Compute" to the stub, so client can access it by "Compute"
            System.out.println("ComputeEngine bound");
        } catch (Exception e) {
            System.err.println("ComputeEngine exception:");
            e.printStackTrace();
        }
    
    客户端代码:

    System.out.println("Entering client");
        String lookupName = "localhost";
        System.setProperty("java.security.policy","file:client.policy");
        System.out.println(System.getProperty("java.security.policy"));
        System.setProperty("rmi.server.codebase", "file:/c:/Users/Brian/Documents/RMI_ClientSide/TestTask.class");
        System.out.println(System.getProperty("rmi.server.codebase"));
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }
        try {
            String name = "Compute";
    
    
    
            Registry registry = LocateRegistry.getRegistry("localhost", 1099);
    
            Compute comp99 = (Compute)registry.lookup("Compute");
    
            System.out.println(comp99.executeTask(new TestTask()));
    
        } catch (Exception e) {
            System.err.println("ComputePi exception:");
            e.printStackTrace();
        }
    
    我被引导相信,从教程 只有客户端需要知道TestTask。。。它不需要/不应该被共享。服务器只需要知道接口任务,而客户端给它接口的实现者。。。我相信在后台,服务器会从客户端代码库下载具体的代码

    我的目录结构是 1.文件/RMI_服务端 2.文件/RMI_客户端 3.文件/RMI_共享

    现在,我正在以编程方式在服务器代码中启动RMI寄存器,而不是在命令行上运行它。我不认为这是我的问题,但在这一点上(经过4个小时的调试),我不知道。我可以用这个代码启动服务器

    问题出在客户端。当我尝试运行客户端代码时,我得到:

    Entering client
    file:client.policy
    file:/c:/Users/Brian/Documents/RMI_ClientSide/TestTask.class
    ComputePi exception:
    java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
        java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
        java.lang.ClassNotFoundException: com.company.TestTask
        at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:355)
        at sun.rmi.transport.Transport$1.run(Transport.java:200)
        at sun.rmi.transport.Transport$1.run(Transport.java:197)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
        at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:276)
        at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:253)
        at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:162)
        at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:227)
        at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:179)
        at com.sun.proxy.$Proxy0.executeTask(Unknown Source)
        at com.company.Main.main(Main.java:46)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
    Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
        java.lang.ClassNotFoundException: com.company.TestTask
        at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:315)
        at sun.rmi.transport.Transport$1.run(Transport.java:200)
        at sun.rmi.transport.Transport$1.run(Transport.java:197)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
    Caused by: java.lang.ClassNotFoundException: com.company.TestTask
    
    好的,当我尝试执行TestTask时,注册表返回它找不到它。我已经尝试了-Djava.rmi.server.codebase=file:/c:/Users/Brian/Documents/rmi_ClientSide/命令行参数和/或System.setProperty(“rmi.server.codebase”,“file:/c:/Users/Brian/Documents/rmi_ClientSide/TestTask.class”)的所有可能的路径组合

    绝对没有任何效果。。。我不知道这是否是注册中心的问题,或者我只是没有在代码库中找到正确的排列。这都在一台机器上,所以我不知道为什么它找不到它

    明确地说。。。需要的文件包括: 1.Client->RMI_ClientSide/bin/../Main.class和TestTask.class 2.Server->RMI_ServerSide/bin/.Main.class和ServerNode.class 3.Shared->RMI_Shared/bin/../RMI_Shared.jar->包含Task.class和Compute.class

    正如我所说,这是三个独立的项目,但包名称是相同的。。。包装公司;巧合的是,我在创建每个项目时没有重命名默认值。我也不知道这是否重要。在将RMI_Shared.jar导入服务器和客户端项目时,当然没有。。。他们都很好

    我发现的另一个答案给人的印象是,共享任务也需要包含TestTask。。。但这没有意义,因为注册中心应该在需要时将类定义向上拉到服务器上。。。这样,客户机可以在服务器上执行任意代码(这是在这个简单的不安全测试中使用的)

    我将非常感谢任何人的帮助。谢谢

    编辑:添加到我的代码库文件夹图像的链接

    请注意,我的项目的目录本身就是documents/。客户端、服务器和帮助程序

    java.rmi.ServerException: RemoteException occurred in server thread
    
    在服务器上找不到该类。您发送了
    com.company.TestTask
    的实例,但服务器的类路径上没有该类,无法通过代码库功能找到该类

    System.setProperty("rmi.server.codebase", "file:/c:/Users/Brian/Documents/RMI_ClientSide/TestTask.class");
    

    您的代码基字符串错误。它不应包括类文件名或作为其包一部分的任何目录。代码库是一个URL列表,这些URL要么是JAR文件,要么是作为包结构头部的目录。

    感谢您的评论-这与我的理解相冲突:这个示例分离了接口、远程对象实现、,将客户端代码分为三个包:计算-计算和任务接口引擎-计算引擎实现类客户端-计算引擎客户端代码和Pi任务实现注意他们的“Pi”类如何实现“任务”。。。计算包是他们的共享包。。。请注意客户端和服务器编译如何使用Compute.jar。但是,服务器不使用客户机包(其中包含“Pi”的定义)。也就是说,当服务器知道任务接口时,它为什么需要具体的TestTask实现。注册表/RMI不是应该从客户机代码库中提取该代码吗?如果可以,服务器将从客户机代码库中提取该类,但您的客户机JVM代码库是一个文件:指向客户机文件系统中某个位置的URL,这在服务器上没有任何意义。代码库URL通常是HTTP或FTP。我完全同意服务器和客户端在不同的机器上,但在这个简单的测试用例中,它们不是。我只需启动一个服务器进程(java-jar RMI_ServerSide.jar)和一个客户机(java-jar RMI_ClientSide.jar)并以“localhost”为目标。它们都共享同一个文件系统,因此应该能够获取该文件。但是,如果这根本不起作用,我就必须弄清楚如何通过http/ftp(这是长期的)托管文件。它不应包括类文件名或作为其包一部分的任何目录。代码库是一个URL列表,这些URL要么是JAR文件,要么是作为包结构头的目录。