Что делать, когда ServerSocket создает IOException и поддерживает работу сервера - PullRequest
5 голосов
/ 12 июня 2010

В основном я хочу создать надежный сервер.

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

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

Что делать в блоке IOException? Серверный сокет неисправен, поэтому его необходимо воссоздать? Например, подождите несколько секунд, а затем

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

Однако, если серверный сокет все еще в порядке, его жалко закрыть и убить все ранее принятые соединения, которые все еще связываются.

РЕДАКТИРОВАТЬ: После некоторых ответов, здесь моя попытка справиться с 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);
            }
        }
    }
}    

Ответы [ 4 ]

4 голосов
/ 12 июня 2010

Если сомневаетесь, вы можете попробовать заново создать сокет сервера, используя тот же порт. Если сокет был закрыт, то создание будет успешным, и вы сможете продолжить обработку новых соединений. Старые соединения исчезли, но это вне вашего контроля, так как сокет был закрыт. Если сокет не был закрыт, то создание нового экземпляра не удастся, так как порт все еще используется, который вы можете просто проигнорировать - т.е. не заменяйте текущую ссылку на сокет сервера.

Как правило, клиенты должны также предполагать, что соединения будут разорваны и что переподключение необходимо. Другими словами, не только сервер должен быть устойчивым - клиенты также должны предвидеть ошибки соединения и переподключаться.

2 голосов
/ 12 июня 2010

Вы можете получить IOException для accept (), если сокет сервера закрыт (вами) или у вас закончились ресурсы, например, файловые дескрипторы. В любом случае, вы ничего не можете с этим поделать. Если serverSocket закрыт (вы можете проверить это), у вас, вероятно, была веская причина для этого. Если у вас закончились ресурсы, вам придется либо увеличить лимит ресурсов, что требует перезапуска приложения, либо у вас есть утечка ресурсов.

1 голос
/ 14 июня 2010

Однако, если сокет сервера все еще в порядке, то его жалко закрыть и убить все ранее принятые соединения, которые все еще связываются.

Обратите внимание, что закрытие сокета сервераНЕ закроет ранее принятые соединения.Как только соединение принято, оно живет отдельной радостной жизнью в другом порту.

1 голос
/ 12 июня 2010

Убедитесь, что вы различаете различные IOException с, которые вы можете получить. Это исключение при создании соединения? Это исключение, если соединение уже установлено?

Единственный код, который вы дали для accept() ing. Вообще говоря, IOException обычно означает ошибку на любом уровне физической сети.

Вероятно, лучшее резервное поведение, которое вы можете реализовать, - это подождать определенный временной интервал, а затем попытаться восстановить соединение. Предположим, что вы, скорее всего, не сможете восстановить соединение, так как вы потеряли сетевое соединение на более чем временный период. Убедитесь, что вы справляетесь с этим изящно. Как уже упоминалось @mdma, это должно поддерживаться и вашими клиентами.

...