Я хотел бы запустить программу на удаленном компьютере с помощью php. Конечная цель – управлять программой с помощью веб-браузера на телефоне или на любом другом компьютере.
Моя программа C получает данные от разных датчиков в течение нескольких десятков минут. Он запускается из командной строки в Linux, и я могу отключить его, нажав клавишу «q» на клавиатуре компьютера. Основной поток – это примерно так:
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); }
Каждый поток выполняет некоторый printf, чтобы дать статус каждого датчика. Я хотел бы отслеживать это значение на своем телефоне и иметь кнопку для завершения удаленной программы.
Я могу успешно отслеживать значения, используя system (), open () или proc_open (). Это проблема getchar в основной программе. Он повесит скрипт php …
<?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"; } } ?>
Использование fwrite($pipes[0], 'q');
работает хорошо, но скрипт php зависает, если я использую fwrite($pipes[0], '');
чтобы программа работала …
EDIT: я инвертировал проблему буферизации $process = proc_open('stdbuf -i0 /home/tristan/www/a.out', $descriptorspec, $pipes, $cwd, $env);
безуспешно…
Кто-нибудь знает, как контролировать значения и отправлять команду в программу интерактивным способом?
Спасибо за помощь!
Были проблемы с кодом PHP выше, которые позволяют вашей программе зависать:
stream_get_contents()
будет висеть вечно, ожидая EOL
который никогда не появляется, когда код C работает в бесконечном цикле. Вам нужно будет использовать stream_set_blocking()
чтобы предотвратить stream_get_contents()
proc_close()
также ожидает навсегда, если процесс не завершился. Что никогда не бывает из-за бесконечного цикла. Вам нужно будет его явно proc_terminate()
с помощью proc_terminate()
(что не имеет особого значения для imo)
Я подготовил пример того, как код не будет висеть, но я должен сказать, что ваш код не имеет большого смысла. Я бы закодировал программу C как демон UNIX, который слушает сокет домена UNIX. Затем вы можете создать простой текстовый протокол обмена для своих команд. Затем подключитесь к сокету в PHP. Но, возможно, я ошибаюсь, так как не знаю ваш сценарий приложения подробно.
Однако здесь идет ваш фиксированный код:
$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"; }
Наконец, я получил то, что хотел использовать каналы в функции system ():
<?php if(isset($_POST['start'])){ system('> /tmp/progOut'); system('mkfifo /tmp/progIn'); $proc = popen('./a.out < /tmp/progIn > /tmp/progOut &', 'r'); } ?>