Чтение вывода после выполнения Linux cmd идет в бесконечный цикл - PullRequest
0 голосов
/ 30 января 2019

Я выполняю cmd из jsch, после завершения команды мне нужно показать вывод команды.во время чтения команды выводит ее на длительное время, и его ns не поступают из цикла while даже после выполнения команды.Вот мой код:

java.util.Properties config = new java.util.Properties(); 
        config.put("StrictHostKeyChecking", "no");


        JSch jsch = new JSch();
        session=jsch.getSession(user, host, 22);
        session.setConfig("PreferredAuthentications","publickey,keyboard-interactive,password");
        session.setPassword(password);

        session.setConfig(config);
        session.connect();
        System.out.println("Connected");

        channel=session.openChannel("shell");
        OutputStream ops = channel.getOutputStream();
        PrintStream ps = new PrintStream(ops, true);

         channel.connect();
         ps.println(cmd);
        InputStream in=channel.getInputStream();
        byte[] tmp=new byte[1024];
        while(channel.getExitStatus() == -1){
          while(in.available()>0){
            int i=in.read(tmp, 0, 1024);
            if(i<0)break;
            System.out.print(new String(tmp, 0, i));
          }
          if(channel.isClosed()){
            System.out.println("exit-status: "+channel.getExitStatus());
            break;
          }
          try{Thread.sleep(3000);}catch(Exception ee){}
        }

Ответы [ 2 ]

0 голосов
/ 26 февраля 2019

Из того, что я наблюдал до сих пор, channel.isClosed() верно только после того, как демон SSH отправил вам все содержимое выходных потоков (stdout и stderr).

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

Решение, которое мы используем, заключается в том, чтобы осторожно потреблять все содержимое stdout и stderr одновременно в главном потоке, а не вызывать read() в любом потоке, если мы не уверены, что он не заблокируется.

        StringBuilder result = new StringBuilder();
        StringBuilder error = new StringBuilder();

        InputStream out = channel.getInputStream();
        InputStream err = channel.getErrStream();

        while(!channel.isClosed() || out.available() > 0 || err.available() > 0) {
            if (out.available() > 0) {
                size = out.read(cbuf);
                if (size > 0) {
                    result.append(new String(cbuf, 0, size));
                } 
                // normally the 'if' is useless as available() guarantee size > 0
                // it's just an extra-precaution
            } else if (err.available() > 0) {
                size = err.read(cbuf);
                if (size > 0) {
                    error.append(new String(cbuf, 0, size));
                }
            } else {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
0 голосов
/ 06 февраля 2019

Я добавил команду exit в конце команды.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...