【问题标题】:Shutting down rmi server cleanly彻底关闭 rmi 服务器
【发布时间】:2013-04-24 14:07:58
【问题描述】:

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

我的服务器代码如下,它有一个关闭服务器的方法

服务器

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

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

关机

公共类关机{

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

我相信这可能是由于客户端没有正确断开连接而只是被“切断”但我不确定如何断开服务器端的连接?

请有人建议。

谢谢

【问题讨论】:

    标签: java rmi


    【解决方案1】:

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

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

    【讨论】:

    • 您能解释一下以下内容:“然后简单地返回”吗?什么回报?
    • @iJava 从方法中正常返回,而不是抛出异常或调用System.exit()。在这种情况下,删除所有 exit() 调用将使控制在方法结束时运行,这将起作用。 return 语句也可以使用。
    • 方法调用的正确顺序是:UnicastRemoteObject.unexportObject(this, true); 然后registry.unbind("rmiServer"); 它在初始化过程中绑定失败时起作用。
    【解决方案2】:

    系统正在按照您的指示进行操作。您告诉它取消导出自身,并将“force”参数设置为 true,这会中止正在进行的调用,因此它取消导出自身并中止正在进行的调用。忽略它,或者如果您坚持对关闭客户端做出干净的响应,请让服务器为取消导出操作启动一个新线程,并稍作延迟,以便关闭调用可以返回到客户端。

    【讨论】:

    • @ejb 我也想关闭客户端,就像数据库连接一样。关闭任何帮助?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多