代码之家  ›  专栏  ›  技术社区  ›  Clayton

如何远程关闭JavaRMI服务器

  •  7
  • Clayton  · 技术社区  · 16 年前

    我有一个非常简单的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
    

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

    2 回复  |  直到 15 年前
        1
  •  15
  •   Clayton    16 年前

    如果有人有类似的问题,我自己就知道了答案。这是我的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){}
    }
    
        2
  •  4
  •   Paul de Vrieze    15 年前

    实际上,仅仅注销并立即调用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();
    }
    

    线程需要能够在将来发生某些事情的同时仍然从退出方法返回。