Question

I want to read & write STDOUT & STDIN respectively of a C application using a web interface that is in PHP. For this I have a test c application "hello.c" that outputs a string after certain sleep, using PHP I execute that C application. I use stream select function in PHP and detect when there is a change in the stdout of that C application. I read the application output but on PHP I am getting status changed on read discriptor cotinuosly even the C application output is complete. My code for c app, PHP and browser output are given below;

hello.c

#include<stdio.h>

void main(void)
{
 int i = 0;

 for(i = 0; i < 5; i++)
    {
            printf("hello world\n");
            sleep(1);
    }

}

PHP

<?php
execute_prog('/var/www/html/test/./hello3');

function execute_prog($exe)
{

    set_time_limit(1800);


        $exe_command = escapeshellcmd($exe);

    $descriptorspec = array(

            0 => array("pipe", "r"),  // stdin -> for execution

            1 => array("pipe", "w"),  // stdout -> for execution

            2 => array("pipe", "w") // stderr 

        );

    $process = proc_open($exe_command, $descriptorspec, $pipes);//creating child process


     if (is_resource($process))
      {
            while(1)
        {
            $write  = NULL; 
            $read   = array($pipes[1]);
            $err    = NULL;
            $except = NULL;

            if (false === ($num_changed_streams = stream_select($read, $write, $except, 0)))
            {
                /* Error handling */
                                echo "Errors\n";
            } 
            else if ($num_changed_streams > 0)
            {
                     /* At least on one of the streams something interesting happened */

                        //echo "Data on ".$num_changed_streams." descriptor\n";

                 if($read)
                 {
                     echo "Data on child process STDOUT\n";

                     $s = fgets($pipes[1]);
                     print $s."</br>";


                     flush();
                 }
                 else if($write)
                 {
                     echo "Data on child process STDIN\n";

                 }
                 else if($err)
                 {
                     echo "Data on child process STDERR\n";

                 }

                $num_changed_streams = 0;
            }


        }

        fclose($pipes[0]);
        fclose($pipes[1]);
        fclose($pipes[2]);
        echo "exitcode: ".proc_close($process)."\n";
    }   


return $ret;
}

?>

Result Of PS Command

 ps -eaf | grep hello
 apache   24157 22641  0 10:01 ?        00:00:00 [hello3] <defunct>

Browser Output

Data on child process STDOUT hello world

Data on child process STDOUT hello world

Data on child process STDOUT hello world

Data on child process STDOUT hello world

Data on child process STDOUT hello world

Data on child process STDOUT

Data on child process STDOUT

Data on child process STDOUT

Any idea why I am continuously getting "Data on child process STDOUT" ? While this text is continuously being displayed the "ps" result remains as shown above.

Please guide.

EDIT I added a tweak, I break the while loop when the result of fgets is empty

 $s = fgets($pipes[1]);

 if(empty($s))
 {
    echo "Empty";
    break;  
 }

now the continuous "Data on child process STDOUT" is not displayed. As I said its a tweak Still I dont know why the read descriptor was getting true even if C application stopped sending data. Anyone please

Was it helpful?

Solution

You miss the moment when the hello program stops its output and terminates (and its process becomes "defunct"). Generally, fgets( $some_file ) returns a string if there is output and returns false if $some_file has reached its end. Thus, if you add this check:

$s = fgets($pipes[1]);
if( $s === false ) {
    // Hello program has finished.
    echo 'Finished', PHP_EOL;
    // Close all descriptors and return...
}

you should terminate successfully.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top