我在本地机器上有一个用java编写的程序。此程序使用jsch连接到远程机器,并在用户界面中的aMessageConsole
上显示输出。
我可以更新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;
}
我不知道问题在哪里。我是说它和剧本配合得很好。
有什么想法吗?
最佳答案
简单的答案是为远程会话分配pty(伪tty)。这可能会导致远程进程在运行时发出其输出,而不是在最后发出所有输出:
exec.setPty(true);
当您通过unix命令行运行程序时,您是通过tty设备与程序通信的。当您通过ssh启动一个程序而不请求会话的pty(tty)时,您将通过一组管道与程序通信,每个管道用于标准输入、输出和错误。
unix程序通常会缓冲它们的输出。缓冲行为内置于大多数C程序使用的标准I/O逻辑中(也由Perl、Python等使用或复制)。当写入tty时,典型的行为是缓冲输出数据,直到写入整行(即程序写入换行符),然后立即将整行写入tty。这就是您在以交互方式运行程序时的体验。
当写入管道或文件时,默认行为是缓冲,直到缓冲区填满为止。缓冲区大小可能为8 KB。这种行为是基于这样一个假设:输出不属于人类,因此程序应该以最有效的方式运行。
您的描述听起来像是程序正在对其输出进行块缓冲,并且在程序完成之前它没有产生足够的输出来刷新缓冲区。您希望程序对其输出进行行缓冲(或者完全取消缓冲)。有几种方法可以做到这一点:
当你以交互方式运行程序时,你会说它工作正常。如前所述,请求ssh会话的pty可能会产生这种行为。
您可以查看系统上是否有类似
stdbuf
或unbuffer
的程序。这些可以用来改变进程的缓冲行为。如果您有相关程序的源代码,则可以在程序执行时在某些点向alter the default buffering behavior或flush the buffer添加逻辑。