它更多是C
或glibc
問題。你將不得不使用fflush(stdout)
。
爲什麼?在終端中運行a.out
並從PHP中調用它有什麼區別?
答案:如果你在終端運行a.out
(是stdin a tty),那麼glibc將使用線路緩衝的IO。但是如果你從另一個程序(在這種情況下是PHP)運行它,並且它的標準輸入是一個管道(或者其他什麼,但不是一個tty)比glibc將使用內部IO緩衝。這就是爲什麼第一個fgets()
塊如果未註釋。欲瞭解更多信息,請點擊這裏article。
好消息:您可以使用stdbuf
命令控制此緩衝。更改$run_string
到:
$run_string = "cd ".$addr_base.";stdbuf -o0 ./a.out 2>&1";
這裏來工作的例子。工作,即使它是使用stdbuf
命令C代碼不關心fflush()
:
啓動子
$cmd = 'stdbuf -o0 ./a.out 2>&1';
// what pipes should be used for STDIN, STDOUT and STDERR of the child
$descriptorspec = array (
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
// open the child
$proc = proc_open (
$cmd, $descriptorspec, $pipes, getcwd()
);
集所有流非阻塞模式
// set all streams to non blockin mode
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking(STDIN, 0);
// check if opening has succeed
if($proc === FALSE){
throw new Exception('Cannot execute child process');
}
讓孩子PID 。我們需要它後來
// get PID via get_status call
$status = proc_get_status($proc);
if($status === FALSE) {
throw new Exception (sprintf(
'Failed to obtain status information '
));
}
$pid = $status['pid'];
調查,直到子進程終止
// now, poll for childs termination
while(true) {
// detect if the child has terminated - the php way
$status = proc_get_status($proc);
// check retval
if($status === FALSE) {
throw new Exception ("Failed to obtain status information for $pid");
}
if($status['running'] === FALSE) {
$exitcode = $status['exitcode'];
$pid = -1;
echo "child exited with code: $exitcode\n";
exit($exitcode);
}
// read from childs stdout and stderr
// avoid *forever* blocking through using a time out (50000usec)
foreach(array(1, 2) as $desc) {
// check stdout for data
$read = array($pipes[$desc]);
$write = NULL;
$except = NULL;
$tv = 0;
$utv = 50000;
$n = stream_select($read, $write, $except, $tv, $utv);
if($n > 0) {
do {
$data = fread($pipes[$desc], 8092);
fwrite(STDOUT, $data);
} while (strlen($data) > 0);
}
}
$read = array(STDIN);
$n = stream_select($read, $write, $except, $tv, $utv);
if($n > 0) {
$input = fread(STDIN, 8092);
// inpput to program
fwrite($pipes[0], $input);
}
}
是您的「用戶」,從網站互動?因爲通過這種方式,用戶似乎不能直接訪問服務器的'STDIN'。 – Passerby 2013-05-03 04:13:19
@Passerby用戶按下按鈕進行編譯,並輸入_x_並將其發送到服務器。但是在輸入_x_之前,服務器必須首先從'STDIN'獲取流並將其發送到網站,以便用戶知道他應該輸入_x_。問題是服務器無法在那一刻得到流.. – dahui 2013-05-03 04:39:52