干净的方式来停止RMI服务器

没有stopServerfunction的RMI服务器工作正常。

public class HelloServer extends UnicastRemoteObject implements HelloInterface { private final static int PORT=1102; private final String serverName="server"; private Timer timer; public HelloServer() throws RemoteException { timer = new Timer(); //At this line a new Thread will be created timer.schedule(new StopServerTask(), 5000); } @Override public String serverResponse(String request) throws RemoteException { return "Hello"+request; } public static void main(String[] args) { try { HelloServer skeleton=new HelloServer(); System.out.println("Starting server"); skeleton.startServer(); System.out.println("Server started"); } catch (RemoteException ex) { ex.printStackTrace(); } } public void startServer() { try { HelloServer skeleton=new HelloServer(); Registry reg=LocateRegistry.createRegistry(PORT); reg.rebind(serverName, skeleton); System.out.println("Server is ready"); } catch (RemoteException ex) { Logger.getLogger(HelloInterface.class.getName()).log(Level.SEVERE, null, ex); } } public void stopServer() { System.out.println("Stopping server"); try { Registry rmiRegistry = LocateRegistry.getRegistry(PORT); HelloInterface myService = (HelloInterface) rmiRegistry.lookup(serverName); rmiRegistry.unbind(serverName); UnicastRemoteObject.unexportObject(rmiRegistry, true); } catch (NoSuchObjectException e) { e.printStackTrace(); } catch (NotBoundException e) { e.printStackTrace(); } catch (RemoteException ex) { Logger.getLogger(HelloServer.class.getName()).log(Level.SEVERE, null, ex); } } class StopServerTask extends TimerTask { @Override public void run() { stopServer(); } } } 

每当抛出调用exception中的stopServer()时

 UnicastRemoteObject.unexportObject(rmiRegistry, true); 

这是堆栈跟踪

 java.rmi.NoSuchObjectException: object not exported at sun.rmi.transport.ObjectTable.unexportObject(ObjectTable.java:153) at java.rmi.server.UnicastRemoteObject.unexportObject(UnicastRemoteObject.java:297) at rmi.HelloServer.stopServer(HelloServer.java:84) 

即使我使用清理服务对象,事情也是一样的

  UnicastRemoteObject.unexportObject(myService, true); 

有人可以提出一种干净的方法来停止服务器,它也会释放端口以供重用。

您需要存储LocateRegistry.createRegistry(),的结果LocateRegistry.createRegistry(),LocateRegistry.createRegistry(),导出它。 目前你正试图取消存根。

我在rmi-server中实现了shutdown-service。 如果我想关闭它,我用密码调用它。 简单示例:

 public interface ShutdownInterface extends Remote { public void shutdownService(String password) throws RemoteException; } 

服务器端实现可能类似于:

 public class ShutdownService extends UnicastRemoteObject implements ShutdownInterface { private static final long serialVersionUID = 1L; private boolean doShutdown = false; public ShutdownService() throws RemoteException { super(); } @Override public void shutdownService(String password) throws RemoteException { if ("abcde12345".equals(password)) { System.out.println("shutdown requested."); this.doShutdown = true; } else { System.out.println("wrong pwd for shutdown"); } } public boolean isDoShutdown() { return this.doShutdown; } 

}

现在服务器本身保留了对此的引用:

 public class BackendServer { public final static int RMI_PORT = 1974; private Registry registry = null; private ShutdownService shutdownService = null; public BackendServer() throws RemoteException { registry = LocateRegistry.createRegistry(RMI_PORT); this.shutdownService = new ShutdownService(); } public void initialize() throws AccessException, RemoteException, AlreadyBoundException { shutdownService = new ShutdownService(); registry.bind("ShutdownService", shutdownService); registry.bind("MyDataService", new MyDataService()); } public void stop() throws NoSuchObjectException { System.out.println("stopping rmi server."); UnicastRemoteObject.unexportObject(registry, true); System.exit(0); } public boolean shouldStop() { return this.shutdownService.isDoShutdown(); } public static void main(String args[]) { try { BackendServer bs = new BackendServer(); bs.initialize(); System.out.println("Server ready."); while (!bs.shouldStop()) { Thread.sleep(1000); } bs.stop(); } catch (Exception e) { System.err.println("Server exception: " + e.toString()); e.printStackTrace(); } } 

}

当然,这可以通过更美观的方式实现,但这应该让您了解如何轻松实现自己的关闭。 您可以从主客户端或您为服务器编写的小型命令行工具调用它。