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

时间:2014-03-13 07:07:32

标签: java rmi

RMI服务器,在没有stopServer功能的情况下工作正常。

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();
        }

        }
}

每当在

中抛出调用异常中的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);

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

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

我在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();
    }
}

}

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