我有一个服务器和一个客户端通过 RMI 进行通信。他们的目标是共享一个简单的对象,一起处理它,然后模拟服务器断开连接。
服务器的名称绑定到 rmiregistry。客户端使用 rmiregistry 获取对服务器的远程引用。然后它使用这个引用来调用一个方法,该方法返回对他们将共享的对象的引用。将通过此共享对象进行进一步的通信。
共享对象是一个 UnicastRemoteObject,服务器拥有它的实现,并有一个方法返回对客户端的引用。
客户端知道共享对象的接口,从服务器获取远程引用,然后对其进行操作。请注意服务器应该返回一个远程引用,而不是一个序列化的副本。
这是共享对象接口
public interface CInterface extends Remote {
boolean testMethod() throws RemoteException;
}
这是它的实现
public class CImpl implements CInterface {
@Override
public boolean testMethod() throws RemoteException {
return false;
}
}
这是服务器的方法,当客户端调用它时应该返回一个远程引用
public CInterface exportRefToC() throws RemoteException {
return new CImpl();
}
如果我从客户端调用它,它会给我这个异常
java.rmi.UnmarshalException:错误解组返回;嵌套异常是:java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException:sandbox.CImpl
如果我这样写,我可以让方法工作并返回远程引用
public CInterface exportRefToC() throws RemoteException {
refToC = new CImpl();
return (CInterface) UnicastRemoteObject.exportObject(refToC, 1099);
}
我不明白为什么我需要再次通过注册表,尽管没有显式绑定名称,只是为了返回远程引用。客户端之前使用 rmiregistry 获得了对服务器的引用,因此引导程序完成。现在,为什么服务器不能在不知道 rmiregistry 端口(1099)的情况下只返回对客户端的引用?
额外的问题,如果服务器想让它与客户端共享的对象不可用(模拟断开连接),有没有比这样做更好的方法
UnicastRemoteObject.unexportObject(refToC, true);
编辑:如果我在共享对象的实现中扩展 UnicastRemoteObject,则该方法的第一个版本有效,但是,unexport 不起作用并返回此异常
java.rmi.ServerException:服务器线程发生RemoteException;嵌套异常是:java.rmi.NoSuchObjectException:对象未导出
EDIT2:再次检查,它确实有效,只需要在返回之前保存引用
public CInterface exportRefToC() throws RemoteException {
refToC = new CImpl();
return refToC;
}