【问题标题】:How to remotely shutdown a Java RMI Server如何远程关闭 Java RMI 服务器
【发布时间】:2008-10-27 18:51:28
【问题描述】:

我有一个非常简单的 Java RMI 服务器,如下所示:

    import java.rmi.*;
    import java.rmi.server.*;

    public class CalculatorImpl extends UnicastRemoteObject implements Calculator {

        private String mServerName;

        public CalculatorImpl(String serverName) throws RemoteException
        {
            super();
            mServerName = serverName;
        }

        public int calculate(int op1, int op2) throws RemoteException
        {
            return op1 + op2;
        }

        public void exit() throws RemoteException
        {
            try{
                Naming.unbind(mServerName);
                System.out.println("CalculatorServer exiting.");
            }
            catch(Exception e){}

            System.exit(1);
        }

        public static void main(String args[]) throws Exception
        {
            System.out.println("Initializing CalculatorServer.");

            String serverObjName = "rmi://localhost/Calculator";

            Calculator calc = new CalculatorImpl(serverObjName);

            Naming.rebind(serverObjName, calc);

            System.out.println("CalculatorServer running.");
        }
}

当我调用 exit 方法时,System.exit(1) 抛出以下异常:

CalculatorServer exiting.
java.rmi.UnmarshalException: Error unmarshaling return header; nested exception is:
        java.io.EOFException
        at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:203)
        at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:126)
        at CalculatorImpl_Stub.exit(Unknown Source)
        at CalculatorClient.<init>(CalculatorClient.java:17)
        at CalculatorClient.main(CalculatorClient.java:29)
Caused by: java.io.EOFException
        at java.io.DataInputStream.readByte(DataInputStream.java:243)
        at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:189)
        ... 4 more
[2]+  Exit 1                  java CalculatorImpl

我在这个方法中做错了什么?

【问题讨论】:

    标签: java rmi


    【解决方案1】:

    如果有人遇到类似问题,我自己想出了答案。这是我的 exit() 方法:

    public void exit() throws RemoteException
    {
        try{
            // Unregister ourself
            Naming.unbind(mServerName);
    
            // Unexport; this will also remove us from the RMI runtime
            UnicastRemoteObject.unexportObject(this, true);
    
            System.out.println("CalculatorServer exiting.");
        }
        catch(Exception e){}
    }
    

    【讨论】:

    • 感谢 unexportObject 示例。
    【解决方案2】:

    实际上只是取消注册并立即调用 System.exit 并不能完全关闭。它基本上在通知客户端消息已完成之前断开连接。有效的方法是启动一个关闭系统的小线程,例如:

    public void quit() throws RemoteException {
      System.out.println("quit");
      Registry registry = LocateRegistry.getRegistry();
      try {
        registry.unbind(_SERVICENAME);
        UnicastRemoteObject.unexportObject(this, false);
      } catch (NotBoundException e) {
        throw new RemoteException("Could not unregister service, quiting anyway", e);
      }
    
      new Thread() {
        @Override
        public void run() {
          System.out.print("Shutting down...");
          try {
            sleep(2000);
          } catch (InterruptedException e) {
            // I don't care
          }
          System.out.println("done");
          System.exit(0);
        }
    
      }.start();
    }
    

    线程需要能够让未来发生一些事情,同时仍然从退出方法返回。

    【讨论】:

    • 整个线程部分是个好主意,但不是必需的。您只需设置 UnicastRemoteObject.unexportObject(this, true) 而不是 UnicastRemoteObject.unexportObject(this, false)。我刚试过同样的问题。
    • 我遇到了同样的问题,设置 unexportObject 的第二个参数没有帮助,但在线程中运行 System.exit 确实有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-04
    • 1970-01-01
    相关资源
    最近更新 更多