3

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 !

11
  • 1
    The question is interesting but vague. Show a little bit more C code and show the PHP code Commented Jul 4, 2013 at 10:53
  • Yes. I respect people who still program in C. Its a powerful programming language with which we can actually access registers. Hope you succeed Commented Jul 4, 2013 at 10:56
  • 2
    If you structure your program to run as a daemon and provide a command line tool to access it, then you'll probably find it a lot simpler to do. Check out how linux does its services: $ service {service-name} restart, $ service {service-name} stop and $ service {service-name} start (cyberciti.biz/tips/…) Commented Jul 4, 2013 at 11:01
  • 1
    You should do as Tom mentioned; you can check this out for how to create a daemon (netzmafia.de/skripten/unix/linux-daemon-howto.html) Commented Jul 4, 2013 at 11:06
  • Perhaps this might help Commented Jul 4, 2013 at 11:12

2 Answers 2

2

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";
}
Sign up to request clarification or add additional context in comments.

Comments

0

I finally got what I wanted using pipes within the system() function :

<?php

if(isset($_POST['start'])){

    system('> /tmp/progOut');
    system('mkfifo /tmp/progIn');

    $proc = popen('./a.out < /tmp/progIn > /tmp/progOut &', 'r');
}
?>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.