客户端

时间:2016-09-08 21:09:12

标签: java intellij-idea rmi classnotfoundexception

同一个标题有几个问题,但没有一个问题帮我解决了我的问题。

我一直在尝试按照这里的教程: https://docs.oracle.com/javase/tutorial/rmi/overview.html

我把一切都放在一个项目中让自己疯了,所以我创建了3个独立的项目:

  1. 服务器 - >它有Main(Driver)和类:ServerNode实现Compute
  2. 客户 - >它有Main(Driver)和class:TestTask实现Task
  3. 共享 - >它有接口:Task和interface:Compute
  4. 这个想法是......两个应用程序都需要了解Interfaces Task(客户端发送给服务器的工作单元)和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. Documents / RMI_ServiceSide 2. Documents / RMI_ClientSide 3. Documents / RMI_Shared

    现在我正在以编程方式在服务器代码中启动rmiregister,而不是在命令行上运行它。我不认为这是我的问题,但在这一点上(经过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 /命令行参数AND /或System.setProperty(“rmi.server.codebase” “,”“file:/ c:/Users/Brian/Documents/RMI_ClientSide/TestTask.class”);

    绝对没有任何效果......我不知道这是rmiregistry的问题,还是我没有在我的代码库中找到正确的排列。这一切都在一台机器上,所以我不知道为什么它在找到它时遇到了问题。

    要明确......必要的文件: 1.客户 - > RMI_ClientSide / bin /.../ Main.class和TestTask.class 2.服务器 - > RMI_ServerSide / bin / .. Main.class和ServerNode.class 3.共享 - > RMI_Shared / bin /.../ RMI_Shared.jar - >包含Task.class和Compute.class

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

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

    我很感激能帮助您实现这一目标。谢谢!

    编辑:添加了指向我的codebase文件夹图像的链接 Codebase directory

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

1 个答案:

答案 0 :(得分:1)

java.rmi.ServerException: RemoteException occurred in server thread

在服务器上找不到的类。您发送了com.company.TestTask的实例,但服务器在其CLASSPATH上没有该类,并且无法通过代码库功能找到它。

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

您的codebase字符串错误。它不应包含类文件名或属于其包的任何目录。代码库是一个URL列表,它们是JAR文件或作为包结构头的目录。