java - Linux命令执行后读取输出将陷入无限循环

标签 java linux jakarta-ee java-io jsch

我正在从 jsch 执行 cmd,命令完成后我需要显示命令输出。在读取命令输出时,它需要很长时间,并且即使在执行命令之后,它的 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){}
        }

最佳答案

根据我迄今为止的观察,只有当 SSH 守护进程向您发送了输出流(stdout 和 stderr)的所有内容时,channel.isClosed() 才是 true。

如果此内容很大,它将无法完全放入 sshd 和您的进程之间的 TCP 连接的缓冲区中,并且 channel 将永远保持打开状态。当 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();
                }
            }
        }

关于java - Linux命令执行后读取输出将陷入无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54437550/

相关文章:

jakarta-ee - 将 ear 文件转换为 war 文件的最佳实践

java - 为什么当我使用变量时我的 vector 的大小更准确?

java - Jvm 需要很长时间才能解析 localhost 的 ip-address

java,mysql - 为什么不能从一个表中获取最后插入的 id 并将其再次插入到另一个表中?

Linux 文件和进程级 I/O 性能指标

php - Linux-Bash 的一些问题

java - 在android中使用kso​​ap2上传的空对象

linux - 在 linux 系统上从 golang 中的 xls 文件中读取值

java - 为什么 servlet 不检索该部分?它显示 null 作为文件名

java - Jsp - 访问 pdf - 使用 URL- "save or open"窗口在单击时显示错误