как правильно закрыть ssh соединение / сессию здесь? - PullRequest
0 голосов
/ 21 июня 2019

У меня есть программа сокет клиент / сервер.Серверная часть подключается через ssh к хосту, запускает сценарий и отправляет каждую строку вывода клиенту.

В приведенной ниже части кода сервера возвращается BufferedReader, содержащий вывод сценария, как это происходит:

public synchronized BufferedReader runScript(<params>) {    
  BufferedReader br = null ;
  try {
      Connection conn = new Connection(host);
      conn.connect();
      ... // authentication part
      Session sess = conn.openSession();
      sess.execCommand("ascript");
      InputStream stdout = new StreamGobbler(sess.getStdout());
      br = new BufferedReader(new InputStreamReader(stdout));
  } catch (Exception e) {
      e.printStackTrace();
  }
  return br;
}

Вышеуказанный метод вызывается из другого серверного класса / кода, как показано ниже, записывая каждую строку BufferedReader для клиента через сокет, чтобы клиент видел текущий вывод сценария во время его выполнения.:

BufferedReader br = new UnixCommandExecutor().runScript(<params>);
String line;
while ((line = br.readLine()) != null) {
      out.writeObject(line);
}

Очевидная проблема с методом runScript заключается в том, что он не закрывает ssh Connection & Session (ganymed ssh lib), поскольку он мгновенно возвращает BufferedReader (если я не ошибаюсь), покаБазовый скрипт все еще выполняется.Если я закрою их перед оператором return, BufferedReader будет неполным.Итак, как мне правильно закрыть соединение / сеанс здесь, как только базовый сценарий завершится?

(Я знаю о попытках с ресурсами и буду его использовать, однако сомневаюсь, что это полностью решит проблему?)

1 Ответ

1 голос
/ 24 июня 2019

Я бы посоветовал вам изменить код так, чтобы вы

  • либо оберните детали в объект и выполните операцию закрытия позже
  • или вы сразу же используете Reader и закрываете соединение после того, как с ним покончено.

Не передавайте считыватель наружу, не поддерживая соединение.

Ниже несколько упрощенный пример того, как это можно сделать.

Если вам нужно выполнить несколько шагов до того, как вы закончите с Reader, вы не сможете обернуть ResultHandler в блок захвата try {...}. В этом случае вам понадобится другой механизм, чтобы в конечном итоге его закрыть.

Но, судя по описанию вашей проблемы, это может быть не так.

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

Пока считыватель все еще получает выходные данные (пока активен входной поток / соединение), вам, вероятно, потребуется выполнить цикл. Каким-то образом вам нужно выяснить, когда ваша операция завершена.

Например, ваш скрипт может закрыть соединение (со стороны сервера), как только это будет сделано, или вернуть что-то конкретное для вас, что вы можете интерпретировать как конец операции.

public class ResultHandler {

    String host;
    Connection conn;
    BufferedReader reader = null;

    public ResultReader(String host) {
        this.host = host;
    }

    public void connect(<params>) throws Exception {

        // if you intend to reuse the object, just check that it was properly cleanedup before
        close();

        conn = new Connection(host);
        conn.connect();
        ... // authentication part

        // you might want to move the actual handling to a different method
        Session sess = conn.openSession();
        sess.execCommand("ascript");
        InputStream stdout = new StreamGobbler(sess.getStdout());
        br = new BufferedReader(new InputStreamReader(stdout));
    }

    public BufferedReader getReader() {
        return this.reader;
    }

    public void close() {
        If (reader != null) {
            reader.close();
        }
        if (conn != null) {
            conn.close();
        }
    }

    public void finalize() {
        close();
    }
}


synchronized void runScript(<params>) {    

  ResultHandler handler;
  try {
        handler = new ResultHandler(host);
        handler.connect();

        // consume the reader for whatever you need to do

  } catch (Exception e) {
      e.printStackTrace();
  } finally {
    // or use try-with-resource and implement the proper interface for that
    if (handler != null) {
        handler.close();
     }
  }
}
...