java 当 ServerSocket 抛出 IOException 并保持服务器运行时该怎么办

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3028543/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 00:00:44  来源:igfitidea点击:

What to do when ServerSocket throws IOException and keeping server running

javanetworkingsockets

提问by s5804

Basically I want to create a rock solid server.

基本上我想创建一个坚如磐石的服务器。

while (keepRunning.get()) {
    try {
        Socket clientSocket = serverSocket.accept();

        ... spawn a new thread to handle the client ...
    } catch (IOException e) {
        e.printStackTrace();
        // NOW WHAT?
    }
}

In the IOException block, what to do? Is the Server socket at fault so it need to be recreated? For example wait a few seconds and then

在 IOException 块中,该怎么办?服务器套接字是否有问题,因此需要重新创建?例如等待几秒钟然后

serverSocket = ServerSocketFactory.getDefault().createServerSocket(MY_PORT);

However if the server socket is still OK, then it is a pity to close it and kill all previously accepted connections that are still communicating.

但是,如果服务器套接字仍然正常,那么很遗憾关闭它并杀死所有先前接受的仍在通信的连接。

EDIT: After some answers, here my attempt to deal with the IOException. Would the implementation be guaranteeing keeping the server up and only re-create server socket when only necessary?

编辑:在回答一些问题之后,我在这里尝试处理 IOException。该实现是否能保证保持服务器正常运行并仅在必要时重新创建服务器套接字?

while (keepRunning.get()) {
    try {
        Socket clientSocket = serverSocket.accept();

        ... spawn a new thread to handle the client ...
        bindExceptionCounter = 0;
    } catch (IOException e) {
        e.printStackTrace();

        recreateServerSocket();
    }
}

private void recreateServerSocket() {
    while (keepRunning) {
        try {
            logger.info("Try to re-create Server Socket");
            ServerSocket socket = ServerSocketFactory.getDefault().createServerSocket(RateTableServer.RATE_EVENT_SERVER_PORT);

            // No exception thrown, then use the new socket.
            serverSocket = socket;
            break;
        } catch (BindException e) {
            logger.info("BindException indicates that the server socket is still good.", e);
            bindExceptionCounter++;

            if (bindExceptionCounter < 5) {
                break;
            }
        } catch (IOException e) {
            logger.warn("Problem to re-create Server Socket", e);
            e.printStackTrace();

            try {
                Thread.sleep(30000);
            } catch (InterruptedException ie) {
                logger.warn(ie);
            }
        }
    }
}    

采纳答案by mdma

If in doubt, you could try re-creating the server socket, using the same port. If the socket has been closed, then the creation will succeed and you can continue processing new connections. The old connections are gone, but that's outside of your control since the socket was closed. If the socket was not closed, then creating a new instance will fail since the port is still in use, which you can just ignore - i.e. don't replace the current server socket reference.

如果有疑问,您可以尝试使用相同的端口重新创建服务器套接字。如果套接字已关闭,则创建将成功,您可以继续处理新连接。旧的连接消失了,但由于套接字已关闭,这超出了您的控制范围。如果套接字未关闭,则创建新实例将失败,因为端口仍在使用中,您可以忽略这一点 - 即不要替换当前服务器套接字引用。

In general, clients should also assume that connections will be broken and that reconnection is necessary. In other words, it's not just the server that has to be robust - clients should also anticipate connection errors and reconnect.

通常,客户端还应该假设连接会中断并且需要重新连接。换句话说,不仅仅是服务器必须健壮——客户端还应该预测连接错误并重新连接。

回答by Peter Lawrey

You can get an IOException on an accept() if the server socket is closed (by you) or you run out of resources, e.g. file handles. Either way, there is not much you can do about it. If the serverSocket is closed (you can test for this) you probably had a good reason to do this. If you run out of resources, you will either have to increase your resource limit, which requires a restart of your application, or you have a resource leak.

如果服务器套接字已关闭(由您关闭)或资源(例如文件句柄)用完,则您可以在 accept() 上获得 IOException。无论哪种方式,您都无能为力。如果 serverSocket 已关闭(您可以对此进行测试),您可能有充分的理由这样做。如果资源用完,您将不得不增加资源限制,这需要重新启动应用程序,或者出现资源泄漏。

回答by volley

However if the server socket is still OK, then it is a pity to close it and kill all previously accepted connections that are still communicating.

但是,如果服务器套接字仍然正常,那么很遗憾关闭它并杀死所有先前接受的仍在通信的连接。

Please note that closing the server socket will NOT close previously accepted connections. As soon as a connection has been accepted it lives a separate, joyful life at a different port.

请注意,关闭服务器套接字不会关闭以前接受的连接。一旦连接被接受,它就会在不同的港口过上独立、快乐的生活。

回答by Yuval Adam

Make sure you differentiate between different IOExceptions you might receive. Is it an exception on creating a connection? Is it an exception once a connection has already been established?

确保您区分IOException您可能收到的不同s。创建连接是例外吗?一旦建立了连接,它是否是一个例外?

The only code you gave is for accept()ing. Generally speaking, an IOExceptionusually means an error on any layer on the physical network.

您提供的唯一代码是用于accept()ing。一般来说,一个IOException通常意味着物理网络上任何一层的错误。

Probably the best fallback behavior you can implement is to wait for a certain time quantum, and then try to reconnect. Assume you most possibly will not be able to reconnect, since you have lost network connection for more than a temporary period. Make sure you handle this gracefully. As @mdma mentioned, this must be supported by your clients as well.

您可以实现的最佳回退行为可能是等待某个时间段,然后尝试重新连接。假设您很可能无法重新连接,因为您已经失去网络连接超过暂时的时间。确保你优雅地处理这件事。正如@mdma 提到的,这也必须得到您的客户的支持。