2013-04-24 80 views
4

我在关闭服务器组件时遇到了一些麻烦,并希望得到一些帮助。干净地关闭rmi服务器

我的服务器代码如下,它必须关闭服务器

服务器

private final String address = "127.0.0.1"; 
    private Registry registry; 
    private int port = 6789; 

    public RmiServer() throws RemoteException { 
     try { 
      registry = LocateRegistry.createRegistry(port); 
      registry.rebind("rmiServer", this); 
     } catch (RemoteException e) { 
      logger.error("Unable to start the server. Exiting the application.", e); 
      System.exit(-1); 
     } 
    } 


    public void shutDownServer() throws RemoteException { 
     int succesful = 0; 
     try { 
      registry.unbind("rmiServer"); 
      UnicastRemoteObject.unexportObject(this, true); 
      Thread.sleep(1000); 
     } catch (NotBoundException e) { 
      logger.error("Error shutting down the server - could not unbind the registry", e); 
      succesful = -1; 
     } catch (InterruptedException e) { 
      logger.info("Unable to sleep when shutting down the server", e); 
      succesful = -1; 
     } 
     catch (AccessException e) { 
      logger.info("Access Exception", e); 
      succesful = -1; 
     } 
     catch (UnmarshalException e) { 
      System.out.println(e.detail.getMessage()); 
      logger.info("UnMarshall Exception", e); 
      succesful = -1; 
     } 
     catch (RemoteException e) { 
      System.out.println(e.detail.getMessage()); 
      logger.info("Remote Exception", e); 
      succesful = -1; 
     } 

     logger.info("server shut down gracefully");  
     System.exit(succesful); 
} 

我的客户端连接正常,没有任何问题,所以关机我创建了一个新的应用程序的方法,复制客户端代码连接,然后调用服务器上的关闭方法

关闭

公共类关机{

private String serverAddress = "127.0.0.1"; 
private String serverPort = "6789"; 
private ReceiveMessageInterface rmiServer; 
private Registry registry; 

public Shutdown(){ 
    try { 
     registry = LocateRegistry.getRegistry(serverAddress, (new Integer(serverPort)).intValue()); 
     rmiServer = (ReceiveMessageInterface) (registry.lookup("rmiServer")); 
     logger.info("Client started correctly"); 
     rmiServer.shutDownServer(); 
     System.exit(0); 
    } 
    catch (UnmarshalException e){ 
     logger.error("Unmarshall exception. Exiting application", e); 
     System.exit(-1); 
    } 
    catch (RemoteException e) { 
     logger.error("Remote object exception occured when connecting to server. Exiting application", e); 
     System.exit(-1); 
    } catch (NotBoundException e) { 
     logger.error("Not Bound Exception occured when connecting to server. Exiting application", e); 
     System.exit(-1); 
    } 
} 

不管我怎么努力我不断收到以下异常;

ERROR com.rmi.client.RMIClient - Unmarshall exception. Exiting application 
java.rmi.UnmarshalException: Error unmarshaling return header; nested exception is: 
    java.net.SocketException: Connection reset 
    at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source) 
    at sun.rmi.server.UnicastRef.invoke(Unknown Source) 
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source) 
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source) 
    at $Proxy0.shutDownServer(Unknown Source) 
    at com.rmi.shutdown.Shutdown.<init>(Shutdown.java:31) 
    at com.rmi.shutdown.Shutdown.main(Shutdown.java:52) 
Caused by: java.net.SocketException: Connection reset 
    at java.net.SocketInputStream.read(Unknown Source) 
    at java.io.BufferedInputStream.fill(Unknown Source) 
    at java.io.BufferedInputStream.read(Unknown Source) 
    at java.io.DataInputStream.readByte(Unknown Source) 
    ... 7 more 

我相信这可能是由于客户端不能正常断开,只是被“切断”,但我不确定是怎么回事断开服务器端?

请有人建议。

谢谢

回答

0

系统正在按照您的要求进行操作。你告诉它自己出口,并且你将'force'参数设置为true,这会中止正在进行的通话,所以它不会自动导出并中止正在进行的通话。只要忽略它,或者如果坚持对关闭客户端进行干净的响应,请让服务器启动一个用于未取出端口操作的新线程,并且延迟时间很短,以便关闭呼叫可以返回到客户端。

+0

@ejb我也想关闭客户端,就像数据库连接。关闭任何帮助吗? – danielad 2013-07-01 12:38:31

5

带有force = true的Unexport不会中止正在进行的调用。总的来说,它会让正在进行的呼叫完成。您的shutDownServer方法几乎是正确的,因为它取消注册远程引用并取消导出它。但是,接下来的工作不起作用。首先,它睡一秒钟。这使呼叫进行中,并保持客户端等待答复。然后关闭代码退出服务器JVM而不从远程调用返回。这会在等待回复时关闭客户端的连接。这就是客户端获取连接重置异常的原因。

要完全关闭,取消注册远程对象,使用force = true(如您所做的那样)取消注册,然后直接返回。这将向客户端发送回复,让其远程呼叫完成,然后退出。回到服务器上,在最后一个进行中的调用完成后,如果没有其他对象被导出,并且没有其他东西保留JVM(例如非守护线程),则JVM将退出。您需要让RMI完成服务器端处理,而不是调用System.exit()

+0

你能解释一下:“然后简单地返回”?什么回报? – 2015-05-24 05:44:46

+0

@iJava通常从方法返回,而不是抛出异常或调用'System.exit()'。在这种情况下,删除所有exit()调用将使控制运行结束的方法,这将工作。 return语句也可以工作。 – 2015-05-25 16:34:39

+0

方法调用的正确顺序是:'UnicastRemoteObject.unexportObject(this,true);'然后 'registry.unbind(“rmiServer”);'当初始化过程中绑定失败时,它的工作方式。 – betontalpfa 2017-02-28 09:02:12