Автоматическое повторное подключение к серверу с помощью сокета в Java

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

Я знаю, что мне нужно реализовать какую-то стратегию ping/pong, если я хочу обнаружить сбой соединения немедленно. Но в моем случае нет необходимости сразу обнаруживать обрыв соединения, если оно вообще обнаруживается (скажем, через несколько минут или часов).

Мои вопросы:

  1. Если я не использую какую-то стратегию pingpong/alive-check и соединение обрывается, получу ли я IOException в логике своего приложения через некоторое время (все будет хорошо, если это займет несколько часов) или возможно, что обрыв соединение вообще не определяется?
  2. Будет ли приведенный ниже код соответствовать моим требованиям? Это немного некрасиво (многие пытаются поймать/пока(true) и даже спать, но мне интересно, можно ли распознать соединение с истекшим временем ожидания через определенное время (например, из-за IOException в блокирующем методе BufferedReader.readLine ).
  3. Помимо вопросов выше, что я мог бы сделать лучше?

    public class Receiver implements Runnable {
    
    private Socket socket;
    private final String host;
    private final int port;
    private final int connectionRetryAfter = 10* 1000;
    
    public Receiver(String host, int port)  { // assignments... }
    
    @Override
    public void run() {
        tryCreateSocket();
        listenToServer();
    }
    
    private void listenToServer() {
        String receivedLine;
        BufferedReader buf;
        while(true) {
            try {
                buf = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while ((receivedLine = buf.readLine()) != null) {
                    // do something with 'inputLine'
                }
            } catch (IOException e) {
                // logging
            } finally {
                closeSocket();
            }
            // At this point, either an exception occured or the stream equals null (which means it's closed?)
            tryCreateSocket();
        }
    }
    
    private void tryCreateSocket() {
        try {
            socket = new Socket(host, port);
        } catch (IOException e) {
            // logging
            try {
                Thread.sleep(connectionRetryAfter);
            } catch(InterruptedException ex) {
                // logging
                Thread.currentThread().interrupt();
            }
            // retry
            tryCreateSocket();
        }
    }
    
    private void closeSocket() {
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                // logging
            }
        }
    }
    

    }


person alapeno    schedule 11.01.2014    source источник


Ответы (2)


listenToServer() обязательно должен выдать IOException, если попытка подключения/повторного подключения не удалась. Рассмотрим случай, когда сервер не работает. Вы действительно хотите вечно зацикливаться на этом методе?

person user207421    schedule 13.01.2014
comment
Спасибо. Если попытка (повторного) подключения не удалась, обязательно будет IOException. Вопрос, будет ли возникать исключение IOException после того, как соединение было успешно установлено и сервер отключился.... Что касается цикла: когда сервер возвращается в сеть, я хочу, чтобы приложение автоматически переподключилось как можно скорее. Есть ли более элегантный способ добиться этого? Этот фрагмент кода выполняется в собственном потоке, поэтому другие действия не будут заблокированы в это время. - person alapeno; 15.01.2014

Одна проблема, которую вам, возможно, следует избегать, заключается в том, что вы выполняете рекурсивный вызов функции tryCreateSocket(). Если ваш клиент отключен в течение очень долгого времени, у вас может не хватить памяти. Более того, когда вы восстанавливаете соединение, стек памяти не освобождается.

Я бы рекомендовал итеративный цикл while, вызывающий tryCreateSocket(), чтобы избежать этой проблемы.

person Daniel Driechlinger    schedule 08.05.2016