【问题标题】:RMI UnmarshalException in server服务器中的 RMI UnmarshalException
【发布时间】:2026-02-10 04:15:02
【问题描述】:

我尝试在 Eclipse(在 Windows 7 x64 上)上复制 http://www.ejbtutorial.com/java-rmi/a-step-by-step-implementation-tutorial-for-java-rmi 中的教程。

我只是复制了代码,所以,假设一切都正确,它应该可以工作。

我不得不更改路径变量,因为 rmicstart rmiregistry 在每个文件夹中都不起作用。现在我的路径变量是这样的:

C:\Program Files\Java\jdk1.7.0_25\bin;C:\OCaml\bin;C:\Program Files (x86)\EasyPH
P-DevServer-13.1VC11\binaries\php\php_runningversion;C:\Program Files (x86)\NVID
IA Corporation\PhysX\Common;C:\Windows\system32;C:\Windows;C:\Windows\System32\W
bem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Nmap

我在开头添加了“C:\Program Files\Java\jdk1.7.0_25\bin”。 现在,当我打开 cmd 并输入数字 start rmiregistry 时,它工作正常。

问题是当我尝试在 Eclipse 上运行服务器时,在 cmd 上启动 rmiregistry 后,它不起作用并出现:

Addition Server failed: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
java.lang.ClassNotFoundException: AdditionInterface

我在教程中设置了代码库,所以我真的不明白发生了什么...... 任何建议都非常感谢。提前致谢。

这是堆栈跟踪:

    java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: AdditionInterface
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:419)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:267)
    at sun.rmi.transport.Transport$1.run(Transport.java:177)
    at sun.rmi.transport.Transport$1.run(Transport.java:174)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:273)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:251)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:377)
    at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
    at java.rmi.Naming.rebind(Naming.java:177)
    at AdditionServer.main(AdditionServer.java:10)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: AdditionInterface
    at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:409)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:267)
    at sun.rmi.transport.Transport$1.run(Transport.java:177)
    at sun.rmi.transport.Transport$1.run(Transport.java:174)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)
    Caused by: java.lang.ClassNotFoundException: AdditionInterface
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.rmi.server.LoaderHandler$Loader.loadClass(LoaderHandler.java:1208)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:270)
    at sun.rmi.server.LoaderHandler.loadClassForName(LoaderHandler.java:1221)
    at sun.rmi.server.LoaderHandler.loadProxyInterfaces(LoaderHandler.java:731)
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:675)
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:612)
    at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:646)
    at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:311)
    at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStream.java:263)
    at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1556)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1512)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1769)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
    ... 13 more

编辑:请注意,即使执行 Addition 类的 rmic,创建存根,总是存在 unmarshallException,即使在 Addition_Stub 而不是 AdditionInterface 上也是如此

【问题讨论】:

    标签: java eclipse rmi unmarshalling codebase


    【解决方案1】:

    RMI Class Loading 不应该通过 RMI 接口加载,而是从外部资源加载,例如 web 中的 URL(这是代码库指向的)。

    因此,如果您在服务器端有一些类,则您要么必须在客户端应用程序的类路径中具有相同的类,要么作为 Web 资源公开可用,反之亦然。

    【讨论】:

    • 我也没有尝试启动客户端,因为我认为如果服务器不工作它是没用的。抱歉我的无知,但我不明白解决方案可能是什么。我的意思是,这似乎是重新绑定期间的错误。
    • 类路径上没有AdditionInterface 类?
    • 如果你的意思是构建路径->源,它选择了整个文件夹,全部包含
    • 我刚把它贴在主要问题上。
    • 所以你在 RMI Server 的类路径中没有类,我在这里指的不是你的服务器应用程序,而是 RMI Registry。如果我是你,我会从应用程序代码中注册所需的类(顺便说一句。我正在我当前的项目中这样做)所以你不会有类路径问题
    【解决方案2】:

    RMI 是很难用的东西。太多安全问题,太多开放端口,太容易被破解。

    但作为决定,我可以建议您将接口和由 RMI 类翻译到一个小 jar 文件,将其传递给 rmiregistry 并且不要设置代码库属性。

    启动rmiregistry的命令,你应该在这里设置你的jar的完整路径:

    rmiregistry -J-classpath -J/home/user/dev/project/project-iface.jar
    

    当你启动服务器时,将它绑定到已存在的rmiregistry,而不是启动它自己的。 客户端使用与接口类完全相同的jar,在启动rmiregistry时使用。

    这可以让您避免远程类加载问题,但如果您的接口类经常更改,则会增加开发过程的复杂性。

    与您的示例相关,您应该执行以下步骤:

    1. 在 Eclipse 中创建另一个项目,将文件 AdditionInterface.java 移动到该项目中。项目应该在 jar 中编译。将其命名为 iface.jar 或类似名称。
    2. 从客户端和服务器端项目中删除 AdditionInterface。
    3. 添加 iface.jar 作为客户端和服务器的依赖项。
    4. 从客户端和服务器中删除不必要的文件 security.policy。
    5. 删除 VM 参数以运行客户端和服务器。
    6. 从客户端和服务器代码中删除行 System.setSecurityManager(new RMISecurityManager());
    7. 构建工件 iface.jar
    8. 在cmd中运行命令:rmiregistry -J-classpath -J/home/grigory/dev/test24804087/out/artifacts/iface_jar/iface.jar
    9. 启动服务器,你应该得到消息“Addition Server is ready”。
    10. 运行客户端。您应该收到消息“结果是:19”

    项目结构示例(适用于 IDEA)

    【讨论】:

    • 所以你建议我从 VM 参数中删除代码库,当我通过“启动 rmiregistry”在 cmd 上启动 rmiregistry 以添加 jar 的类路径时?那么我应该在 AdditionServer 上更改什么?对不起,但在这方面我真的一团糟..