JSch ChannelExec OutputStream没有显示程序输出。但它适用于shell脚本

时间:2018-01-10 17:53:46

标签: java linux shell ssh jsch

我在本地机器上用java编写了一个程序。该程序使用JSch连接到远程计算机,并在用户界面的MessageConsole上显示输出。

即使我的启动脚本没有终止并输出随机数,我也可以更新UI中的MessageConsole。我可以阅读OutputStream并在MessageConsole上显示。它运作得非常好。

我的问题是启动C程序后的输出。 OutputStream上没有任何内容。 仅在程序完全终止时才会显示输出。 所有输出都是用

完成的
printf

std::cout

如果我手动登录远程机器并手动启动程序,我的终端会立即显示所有输出。

我使用ChannelExec启动远程计算机上的程序:

String program = "sudo ./foo/bar.out";
String continousOutput = "sh ~/foo/bar.sh";
//ProcessWorker(String command, SSHSession ssh, GUI gui)
pw = new ProcessWorker(program, ssh, this);
pw.execute();

ProcessWorker pw是一个SwingWorker类,用于在后台保持连接打开并更新GUI而不将其锁定。

这段代码可以完成所有繁琐的工作。 SSH连接已经建立并且可以正常工作。

protected Void doInBackground() throws Exception {
    try {
        exec = ssh.session.openChannel("exec");
        //command  is the String  program or continousOutput
        ((ChannelExec)exec).setCommand(command);

        exec.setInputStream(null);

        ((ChannelExec)exec).setErrStream(System.err);
        InputStream in = exec.getInputStream();
        exec.connect();

        byte [] tmp = new byte[1024];
        while(true) {
            while(in.available()>0) {
                int i = in.read(tmp, 0, 1024);
                if(i<0)break;
                String response = new String(tmp, 0, i);
                check(response); //parse response
                System.out.println(response);
                //this.publish(); //desperate try to get something
            }
            if(exec.isClosed()) {
                if(in.available() > 0) continue;
                System.out.println("exit-status: " + exec.getExitStatus());
                break;
            }
            try {Thread.sleep(1000);} catch(Exception ee) {}
        }

        exec.disconnect();
    } catch (JSchException | IOException e) {
        e.printStackTrace();
    }

    return null;
}    

我对这个问题没有更多的想法。我的意思是它与脚本完美搭配。

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

简短的回答是为远程会话分配PTY(伪TTY)。这可能会导致远程进程在其运行时发出其输出,而不是在结束时发出:

exec.setPty(true);

当您通过unix命令行运行程序时,您正在通过TTY设备与程序通信。当您通过SSH 启动程序而不为会话请求PTY(TTY)时,您将通过一组管道与程序通信,每个管道用于标准输入,输出和错误。< / p>

Unix程序通常会缓冲其输出。缓冲行为内置于大多数C程序使用的标准I / O逻辑中(并且也由perl,python等使用或复制)。写入TTY时,典型的行为是缓冲输出数据,直到写入整行(即程序写入换行符),然后将整行写入TTY。这是您以交互方式运行程序时的体验。

写入管道或文件时,默认行为是缓冲,直到填充缓冲区。缓冲区的大小可能是8 KB。这种行为是基于输出不是人类的假设,因此程序应该以最有效的方式运行。

您的描述听起来像程序是块缓冲其输出,并且在程序完成之前它没有产生足够的输出来刷新缓冲区。您希望程序对其输出进行行缓冲(或者完全取消缓冲)。有几种方法可以做到这一点:

  1. 您说交互式运行程序时程序正常运行。正如我所指出的,为ssh会话请求PTY可能会产生这种行为。
  2. 您可以查看系统上是否有stdbufunbuffer等程序。这些可用于改变进程的缓冲行为。
  3. 如果您有相关程序的源代码,则可以在程序执行时在某些点向alter the default buffering behaviorflush the buffer添加逻辑。