关闭 RMI 服务器时出现问题

Issue when closing a RMI server

我在远程关闭 RMI 服务器时遇到了一些麻烦。在我的程序中,客户端需要连接到 RMI 中间件服务器,而 RMI 中间件连接到 3 个不同的 RMI 服务器(flightManager、carManager 和 roomManager)。客户端可以向中间件提交关闭命令。然后中间件应该关闭 3 个服务器和它自己。但是在我关闭 carManager 之后,中间件立即关闭并让另外 2 个服务器保持活动状态。

中间件连接3个管理器并接收3个管理器的存根,当它接收到关闭调用时,它执行以下功能:

public void shutdown() throws RemoteException{
     try{
         this.carManager.shutdown();
         this.flightManager.shutdown();
         this.roomManager.shutdown();
         UnicastRemoteObject.unexportObject(this, true);

         System.out.println("Server exiting.");
        }
        catch(Exception e){}
     System.exit(0);
}

这是 3 个不同管理器的代码,它扩展了 ResourceManger 并为中间件提供了一个存根作为 IResourceManager。

public class RMIResourceManager extends ResourceManager 
{
private static String s_serverName = "Server";
private static String s_rmiPrefix = "test";

public static void main(String args[])
{
    if (args.length > 0)
    {
        s_serverName = args[0];
    }

    // Create the RMI server entry
    try {
        // Create a new Server object
        RMIResourceManager server = new RMIResourceManager(s_serverName);

        // Dynamically generate the stub (client proxy)
        IResourceManager resourceManager = (IResourceManager)UnicastRemoteObject.exportObject(server, 0);

        // Bind the remote object's stub in the registry
        Registry l_registry;
        try {
            l_registry = LocateRegistry.createRegistry(1099);
        } catch (RemoteException e) {
            l_registry = LocateRegistry.getRegistry(1099);
        }
        final Registry registry = l_registry;
        registry.rebind(s_rmiPrefix + s_serverName, resourceManager);

        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                try {
                    registry.unbind(s_rmiPrefix + s_serverName);
                    System.out.println("'" + s_serverName + "' resource manager unbound");
                }
                catch(Exception e) {
                    System.err.println((char)27 + "[31;1mServer exception: " + (char)27 + "[0mUncaught exception");
                    e.printStackTrace();
                }
            }
        });                                       
        System.out.println("'" + s_serverName + "' resource manager server ready and bound to '" + s_rmiPrefix + s_serverName + "'");
    }
    catch (Exception e) {
        System.err.println((char)27 + "[31;1mServer exception: " + (char)27 + "[0mUncaught exception");
        e.printStackTrace();
        System.exit(1);
    }

    // Create and install a security manager
    if (System.getSecurityManager() == null)
    {
        System.setSecurityManager(new SecurityManager());
    }
}

public RMIResourceManager(String name)
{
    super(name);
}
}

最后还有一个 ResourceManager Class 实现了 IResourceManager。里面有关机功能。

public class ResourceManager implements IResourceManager{

        public void shutdown() throws RemoteException{
            System.exit(1);
    }
}

似乎任何管理器的终止都会导致中间件的终止。中间件中的关闭函数执行 "this.carManager.shutdown();" 行并且从不执​​行上面的行。我该如何处理这个问题?

图片显示问题:客户端输入"shutdown"。然后 carManager 关闭,中间件立即关闭。 flightManager 和 roomManager 保持活动状态。

我认为你的问题是你的 shutdown() 实现实际上在与客户端交互的过程中关闭了服务器 - 所以客户端存根看到连接断开,因此抛出异常(你请参阅您的屏幕截图)- 在尝试关闭其他两个客户端之前中止该客户端。

您可能希望实现您的服务器,以便在调用 shutdown() 时注销该服务器(因此不再接受客户端连接),然后启动延迟线程以实际关闭应用程序 - 即这样,您所在的电话将 return 通常发送给客户,然后客户可以继续。

或者,我猜你可以将对 shutdown() 的三个调用中的每一个都包装在一个 try/catch 中,这样你就可以忽略每个客户端将抛出的异常并继续告诉下一个服务器关闭...