I would like to run a C program on a remote computer using php. The final goal is to control the program using a web browser on a phone or any other computer.
My C program is acquiring data from different sensors during a few tens of minutes. It runs from command line in linux and I can turn it off by pressing 'q' key on the computer keyboard. The main thread is something like this :
int main(){
printf("Program is running... Press 'q' <enter> to quit\n");
fflush(stdout);
//create one thread per sensor
while (getchar() != 'q'){
}
//ask the threads to terminate
return(0);
}
Each thread perform some printf to give the status of each sensor. I would like to monitor these value on my phone and have a button to terminate the remote program.
I can sucessfully monitor the values using system(), open() or proc_open(). It problem is the getchar in the main program. It hang the php script...
<?php
if(isset($_POST['start'])){
$descriptorspec = array(
0 => array("pipe", "r"), // // stdin est un pipe où le processus va lire
1 => array("pipe", "w"), // stdout est un pipe où le processus va écrire
2 => array("file", "/tmp/error-output.txt", "a") // stderr est un fichier
);
$cwd = '/tmp';
$env = array();
$process = proc_open('/home/tristan/www/a.out', $descriptorspec, $pipes, $cwd, $env);
if (is_resource($process)) {
fwrite($pipes[0], 'q');
fclose($pipes[0]);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
$return_value = proc_close($process);
echo "La commande a retourné $return_value\n";
}
}
?>
Using fwrite($pipes[0], 'q'); works good but the php script hangs if I use fwrite($pipes[0], ''); in order to keep the program running...
EDIT: I invertigated the buffering issue $process = proc_open('stdbuf -i0 /home/tristan/www/a.out', $descriptorspec, $pipes, $cwd, $env); without success...
Does anyone have a clue on how to both monitor values and send command to the program in an interactive way ?
Thanks for you help !
There were two problems with the PHP code above which let your program hang:
stream_get_contents() will hang forever, waiting for an EOL which never appears as the C code runs in an endless loop. You'll have to use stream_set_blocking() to prevent stream_get_contents() from blocking
proc_close() also waits forever unless the process has terminated. Which does never happen because of the endless loop. You'll have to terminate it explicitly using proc_terminate() (which makes not much sense at all imo)
I've prepared an example how the code would not hang, but I need to say, that your code makes not much sense. I would code the C program as a UNIX daemon which listens to a UNIX domain socket. Then you can design a simple text-based communication protocol for your commands. Then connect to the socket in PHP. But maybe I'm wrong as I don't know your application scenario in detail.
However here comes your fixed code:
$descriptorspec = array(
0 => array("pipe", "r"), // // stdin est un pipe où le processus va lire
1 => array("pipe", "w"), // stdout est un pipe où le processus va écrire
2 => array("file", "/tmp/error-output.txt", "a") // stderr est un fichier
);
$cwd = '/tmp';
$env = array();
$process = proc_open(__DIR__ . '/a.out', $descriptorspec, $pipes, $cwd, $env);
if (is_resource($process)) {
fwrite($pipes[0], ' ');
fclose($pipes[0]);
// set stream to unblocking mode
stream_set_blocking($pipes[1], 0);
// now the following line will not wait forever
// for an EOF
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
// proc_close will wait until the process has finished - forever in this case
// if you want to terminate the process. You'll have to terminate it explicitely
proc_terminate($process);
$return_value = proc_close($process);
// if you want to have a meaningful return value
// you'll have to implement a handler for SIGTERM
// in your C program
echo "La commande a retourné $return_value\n";
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With