经过2天的谷歌搜索,堆叠流动并在其他论坛寻找答案后,我终于放弃了,希望能在这里找到答案!
我在使用简单的RMI客户端 - 服务器应用程序时遇到了一个令人讨厌的问题,尽管看起来(或者我只是遗漏了一点点)是RMI的一个众所周知的问题。
我正在使用Eclipse和m2eclipse(Maven集成)进行依赖关系管理。我的项目结构如下: - 客户端:客户端代码,依赖于共享 - 服务器:服务器代码,对共享的依赖性 - 共享:服务器和客户端之间的远程接口和共享类 - integrationtest:测试项目,同时具有客户端和服务器的依赖性
远程接口客户端可以调用:
public interface IServerReceiver extends Remote, Serializable {
void connect(long clientId) throws RemoteException;
}
此接口位于共享项目中,其中客户端和服务器都具有依赖关系,因此它位于客户端的类路径中。
Server类负责创建注册表并导出远程对象(ServerReceiver实现IServerReceiver):
registry = LocateRegistry.createRegistry(rmiRegistryPort);
serverReceiver = new ServerReceiver(rmiRegistryPort);
registry.rebind(IConstants.RMI_SERVER_RECEIVER_ID, UnicastRemoteObject.exportObject(serverReceiver, 0));
启动服务器时,通过定义-Djava.security.policy为服务器的JVM提供安全策略文件(尽管我不认为这与此处描述的问题有关。)
负责将客户端连接到服务器的类是ServerConnector类:
...
public ServerConnector() {
...
registry = LocateRegistry.getRegistry(serverRMIHost, serverRMIPort);
serverReceiver = (IServerReceiver) registry.lookup(IConstants.RMI_SERVER_RECEIVER_ID);
serverReceiver.connect(client.getId());
...
}
Client类的构造函数看起来像这样(省略了一些行):
public Client(..) {
....
serverConnector = new ServerConnector(serverRMIHost, serverRMIPort, this);
....
}
与服务器一样,客户端也会获得安全策略文件。
当我启动集成测试创建服务器然后启动客户端时:一切正常,并且connect() - 方法返回预期的结果。
但是,当我尝试正常启动Server实例,然后启动尝试connect()到服务器的客户端实例时,会抛出以下异常:
Caused by: java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: assign2.comm.ServerReceiver_Stub
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at assign2.comm.ServerConnector.<init>(ServerConnector.java:65)
在寻找答案时,最突出的是:客户端必须能够访问服务器接口定义(IServerReceiver)。但是,对我来说,似乎就是这种情况,因为适当的依赖关系到位(客户端 - >共享,服务器 - >共享,共享的IServerReceiver)。 我不太了解的异常的另一个方面是:自JDK 1.5以来,不再需要通过rmic生成存根,并且通过动态代理实现。因此,客户端只需要访问接口IServerReceiver即可创建动态代理。为什么他会抱怨根本找不到ServerReceiver_Stub类呢?
由于集成测试成功运行并且在该测试中客户端也可以访问IServerReceiver接口的实现,我是正确的假设客户端不仅需要访问远程接口而且还有它的实施吗?
我现在很困惑,所以也许你可以帮我解释一下这件事情?感谢您阅读了这篇长篇文章! ; - )
干杯, 克里斯
答案 0 :(得分:1)
我同意,您不需要存根,因为您在导出对象时提供端口号。唯一的解释是生成的存根被绑定而不是动态存根。我会删除任何存在的存根文件并重新测试。如果服务器需要存根而没有存根,则它应该在导出时失败,而不是在有人查找时。
我是否正确地假设客户 不仅需要访问遥控器 界面也是它的 执行?
没有。它只需要存根。实施是远程的。这就是整个想法。但是它还需要存根所依赖的任何类,即远程接口和它所依赖的任何类,依此类推,直到关闭。
我还有一些问题:
答案 1 :(得分:1)
IServerReceiver
不应为Serializable
。我的猜测是你的服务器实例是通过网络而不是代理发送的。