2013-03-20 4 views
2

Я пытаюсь написать stdin и читать из stdout (и stderr) из внешней программы, не меняя код.как связаться с программой с другой внешней программой

Я пробовал использовать именованные каналы, но stdout не отображается до тех пор, пока программа не будет завершена, а stdin будет работать только на первом входе (тогда cin равно null).

Я попытался использовать/proc/[pid]/fd, но это только запись и чтение с терминала, а не программы.

Я пробовал писать файл символьного устройства для этого, и он работал, но только по одной программе за раз (это нужно для работы по нескольким программам за раз).

на данный момент, насколько я знаю, я мог бы написать драйвер, который работал для мультиплексирования io через несколько программ, но я не думаю, что это «правильное» решение.

Основной целью этого является просмотр фида программы через веб-интерфейс. Я уверен, что должно быть что-то сделать. есть ли что-то, что я не пробовал, что было сделано раньше?

+0

Это может помочь: http: // stackoverflow.com/questions/43116/how-can-i-run-an-external-program-from-c-and-parse-its-output Если вам нужно прочитать stdout и stderr процесса, вы можете выполнить его с помощью перенаправление stderr на stdout, как этот пример: "popen ("/bin/ls/etc/2> & 1 "," r "); – JustAnotherCurious

ответ

5

Типичный способ сделать это:

  1. Создать анонимные трубы (не названные трубы) с pipe(2) системного вызова для стандарта нового процесса потоков
  2. вызов fork(2) нереститься Дочерний процесс
  3. close(2) соответствующие концы труб как у родителя, так и у ребенка (например, для трубы stdin, закрыть конец чтения в родительском элементе и закрыть конец записи в дочернем элементе, наоборот для труб stdout и stderr)
  4. Использования dup2(2) в ребенке, чтобы скопировать файл трубы дескрипторов на дескрипторы файлов 0, 1 и 2, а затем close(2) остальные старых дескрипторы
  5. exec(3) внешнего приложение в дочернем процессе
  6. В родительском процессе, одновременно писать к детской трубе stdin и читать из труб ребенка stdout и stderr. Однако, в зависимости от того, как ведет себя ребенок, это может легко привести к тупиковой ситуации, если вы не будете осторожны. Один из способов избежать тупиковой ситуации - создать отдельные потоки для обработки каждого из трех потоков; другим способом является использование системного вызова select(2), чтобы дождаться, пока один из потоков не будет считан/записан без блокировки, а затем обработать этот поток.

Даже если вы все это сделаете правильно, вы все равно можете не видеть выход вашей программы сразу. Обычно это происходит из-за буферизации stdout. Обычно, когда stdout идет на терминал, он буферизируется по строке - он становится покрасневшим после каждой новой строки. Но когда stdout - это канал (или что-то еще, что не является терминалом, например файлом или сокетом), он полностью буферизируется и записывается только тогда, когда программа выводит данные с полным объемом буфера (например, 4 КБ).

Многие программы имеют параметры командной строки, чтобы изменить их поведение буферизации. Например, grep(1) имеет флаг --line-buffered, чтобы заставить его буферизовать свой вывод, даже когда stdout не является терминалом. Если ваша внешняя программа имеет такую ​​возможность, вы, вероятно, должны ее использовать. Если нет, все равно можно изменить поведение буферизации, но вы должны использовать некоторые подлые трюки - см. this question и this question для того, как это сделать.

+1

ничего себе, очень информативный. спасибо – tay10r

+1

Я бы предложил использовать 'poll (2)' вместо 'select (2)'. И 'exec (3)' фактически может быть 'execve (2)', который вызывает 'exec (3)'. Хорошая книга, объясняющая, что это http://advancedlinuxprogramming.com/ –

+0

+1, отличный ответ –

Смежные вопросы