2011-12-27 3 views
3

В основном я хочу сделать в C (и без буферизации) такой же, как это баш-скрипт:C: Как перенаправить именованный канал STDIN/из дочернего процесса

#!/bin/sh 
cat ./fifo_in | myprogram > ./fifo_out 

Другими словами, я хочу exec «myprogram» и перенаправить его stdin и stdout на две трубы, которые были созданы ранее.

Другая программа служит для подачи данных в fifo_in и чтения из fifo_out.

Конечно, было бы легко просто прочитать из ./fifo_in, буфера его в родительском и написать стандартный ввод MyProgram (и реверс для стандартного вывода и ./fifo_out), но я думаю, что есть, вероятно, способ, чтобы «MyProgram» чтение/запись непосредственно от/до fifos без буферизации в родительском процессе.

Edit:

ответ Eugen, кажется, правильный, но я не могу заставить его работать.

Я использую эту функцию на C-стороне, которая, кажется, правильно мне:

pid_t execpipes(const char *wd, const char *command, const char *pipename) 
{ 
char pipename_in[FALK_NAMESIZE]; 
char pipename_out[FALK_NAMESIZE]; 
strcpy(pipename_in, FALKPATH); 
strcat(pipename_in, "/"); 
strcat(pipename_in, FALK_FIFO_PATH); 
strcat(pipename_in, "/"); 
strncat(pipename_in, pipename, FALK_NAMESIZE-2); 
strcpy(pipename_out, pipename_in); 
strcat(pipename_out, "R"); 

pid_t pid; 
pid = fork(); 
if (pid < 0) 
{ //Error occured 
    perror("fork"); 
    exit(1); 
} 
if (pid == 0) 
{ 
    chdir(wd); 
    d("execpipes: pipename_in=\"%s\"\n", pipename_in); 
    d("   pipename_out=\"%s\"\n", pipename_out); 
    freopen(pipename_in,"r",stdin); 
    freopen(pipename_out,"w",stdout); 

    d("execpipes: command=\"%s\"\n", command); 

    execl("/bin/sh", "sh", "-c", command, (char *)NULL); // using execv is probably faster 
    // Should never get here 
    perror("execl"); 
    exit(1); 
} 
return pid; 
} 

Я читать и писать трубы из РНР-скрипта (только соответствующая часть размещена):

$pipe_in = fopen($fp.$pipename, "w"); 
$DEBUG .= "Write to pipe_in\n"; 
$ret = fwrite($pipe_in, $in); 

$pipe_out = fopen($fp.$pipename.'R', "r"); 
$DEBUG .= "Read from pipe_out\n"; 
$atext = fread($pipe_out, 200000); // Program hangs here 

Программа запускается правильно, правильно принимает входные данные через $pipe_in, обрабатывает данные правильно и (потому что она работала нормально в течение многих месяцев). Я предполагаю, что она корректно выводит данные на стандартный вывод, но когда я пытаюсь читать с $pipe_out, висит. Я знаю, что сами трубы настроены правильно, потому что, если я не открываю $pipe_out, программа не получает никакого ввода - что имеет смысл, потому что нет читателя для $pipe_out, и поэтому конвейер не завершен. Поэтому я могу открыть $pipe_out, но я ничего не могу прочитать от него, что довольно странно.

Edit2:

Программа теперь работает, спасибо, ребята - По какой-то причине первой трубы должна быть закрыта, прежде чем вы можете прочитать из второй трубы:

$pipe_in = fopen($fp.$pipename, "w"); 
$pipe_out = fopen($fp.$pipename.'R', "r"); 
$DEBUG .= "Write to pipe_in\n"; 
$ret = fwrite($pipe_in, $in); 
fclose($pipe_in); 

$DEBUG .= "Read from pipe_out\n"; 
$atext = fread($pipe_out, 200000); 
fclose($pipe_out); 

unlink($fp.$pipename); 
unlink($fp.$pipename.'R'); 
+0

Вы пишете источник для 'myprogram' или для какой-либо другой программы, которая« называет »' myprogram'? – pmg

+1

Любые причины злоупотреблять «кошкой»? Почему бы не использовать: 'myprogram < ./fifo_in >./Fifo_out'? –

+0

Нет причин использовать кошку, сценарий bash - это просто, чтобы уточнить, что должна делать C-программа. – Robby75

ответ

2

Я бы написать небольшую обертку для mypr ogram, что делает

freopen("./fifo_in","r",stdin) 
freopen("./fifo_out","w",stdout) 

(Ofcourse не с постоянными путями!), то execve MyProgram

+0

Спасибо, я использовал это на стороне С (см. Редактировать выше), но система зависает при попытке чтения из fifo_out. – Robby75

0

Korn оболочка поддерживает coprocesses, который я думаю, что эффективно делает то, что вы спрашиваете: чтение из трубы и писать в канал (который может быть STDOUT и стандартного ввода процесса C)

http://www.dartmouth.edu/~rc/classes/ksh/coprocesses.html 
+0

Но как вы это делаете программно с C? –

+0

Я думал, что OP хочет использовать существующий код C и хочет оболочку оболочки. –

0

Как насчет

myprogram <./fifo_in> ./fifo_out 

?

Что касается избавления от буферизации: поскольку ваша программа напрямую читает/записывает трубы, буферизация не должна причинять вам вреда.

Важным моментом является то, что процесс, который пишет fifo_in, должен быть правильно очищен, поэтому вам не нужно ждать.То же самое относится и к вашему результату: как только «рабочий блок» будет завершен, промойте свой stdout, который сделает данные доступными для тех, кто читает выходной канал.

Но вы не можете ничего сделать в myprogram, чтобы писатель fifo_in смыл свои буферы.

[EDIT] Чтобы сделать это из C (без помощи оболочки), используйте следующий код:

- Put the names of the two pipes into local variables on the stack 
- Call `fork()`. If that returns '0', then open the two fifos with `freopen()` [like Eugen suggested][1] 
- Call `execve` to launch the real exec. 

Это (в двух словах), что оболочка делает, когда он выполняет команду , Убедитесь, что родительский процесс (тот, где fork() возвращает PID! = 0) обрабатывает сигнал SIGCHLD

+0

Так вы можете сделать это из оболочки. Но ОП спрашивает, как он будет делать это из своего собственного процесса, используя C. –

0

Возможно, вы ищете named pipe? Например:

mkfifo fifo_in 

В качестве тестовой заглушки для my_program.c, чтобы читать fifo_in через буферный stdin:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

int main(void) { 
    char buf[80]; 
    if (!freopen("./fifo_in", "r", stdin)) { 
     perror("freopen"); 
     exit(EXIT_FAILURE); 
    } 
    while (!ferror(stdin)) { 
     while (fgets(buf, sizeof buf, stdin)) 
     fputs(buf, stdout); 
     sleep(1); 
    } 
    return 0; 
} 

Тогда как испытание для писателя, используя bash оболочки:

for x in {1..10}; do 
    echo $x 
    echo $x >> fifo_in 
    sleep 1 
done 

Примечания:

  • Я бы предпочел использовать небуферизованный ввод-вывод.
  • Писатель, по крайней мере, на моей машине, блокирует до появления читателя.
  • Читатель, в этом примере, не может определить, когда писатель закончил.
Смежные вопросы