2014-01-05 3 views
3

У меня большие проблемы при выполнении того, что я сказал в заголовке. В принципе, мне нужна программа, скажем, broadcast.c, которая принимает вход от пользователя, а затем отправляет этот вход на вход двух процессов. Так что, если бы запустить эту команду: ./broadcast prog1 PROG2Перенаправить однонаправленный поток одного процесса на два процесса

Это заблокирует ожидает ввода от пользователя и затем посылает этот вход в prog1 и Prog2,.

Теперь, я хочу использовать трубы, вещь, я не знаю, нужно ли мне использовать 1 трубу или 2 трубы.

broadcast.c

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

    int main(int argc, char* argv[]) { 
     int fds1[2], fds2[2]; 
     char buffer[120]; 
     pipe(fds1); 
     pipe(fds2); 

     if (fork() == 0) { 
      close(0); 
      dup(fds1[0]); 
      close(fds1[0]); 
      close(fds1[1]); 
      execl(argv[1], argv[1], NULL); 
     } 

     if (fork() == 0) { 
      close(0); 
      dup(fds2[0]); 
      close(fds2[0]); 
      close(fds2[1]); 
      execl(argv[2], argv[2], NULL); 
     } 

     while(read(0, buffer, 120) != 0) { 
      printf("lido: %s\n", buffer); 
      write(fds1[0],buffer,120); 
      write(fds2[0],buffer,120); 
     } 

     close(1); 
     dup(fds1[1]); 
     dup(fds2[1]); 
     exit(0); 
    } 

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

На данный момент я просто хочу, что когда я делаю: ./broadcast prog1 PROG2 Пользователь вводит: Привет

Выход: prog1 говорит: Привет! prog2 говорит: Привет!

В основном prog1 и PROG2 только печать с помощью чтения на дескриптором 0.

+0

Google «Юникс тройник». – cHao

+0

Хум интересно. Не знал об этом. Но можно ли это сделать с помощью простых вилок и дубликатов? – luispcosta

+0

Не без кода для чтения ввода FD и записи данных на каждый выходной FD, насколько я знаю. – cHao

ответ

0

Я хочу программу, скажем, broadcast.c, которая принимает входные данные от пользователя и затем отправляет этот вход на вход двух процессов. Так что, если бы запустить эту команду: ./broadcast prog1 prog2

Вы могли бы реализовать broadcast команду с помощью bash:

$ tee >/dev/null >(prog1) >(prog2) 

tee читает из стандартного ввода и посылает его prog1 и prog2. tee по умолчанию дублирует stdin на stdout, поэтому >/dev/null используется для его подавления.

Существует также pee команда из moreutils package:

$ pee prog1 prog2 

Он делает именно то, что вы хотите. Он использует popen() для запуска дочерних процессов. Реализация очень проста, здесь весь исходный код (pee.c от git://git.kitenet.net/moreutils):

#include <stdlib.h> 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/wait.h> 

/* Licensed under the GPL 
* Copyright (c) Miek Gieben, 2006 
*/ 

/* like tee(1), but then connect to other programs using 
* pipes _and_ output to standard output 
*/ 

int 
close_pipes(FILE **p, size_t i) 
{ 
    int ret=EXIT_SUCCESS; 
    size_t j; 
    for (j = 0; j < i; j++) { 
     int r = pclose(p[j]); 
     if (WIFEXITED(r)) 
      ret |= WEXITSTATUS(r); 
     else 
      ret |= 1; 
    } 
    return ret; 
} 

int 
main(int argc, char **argv) { 
    size_t i, r; 
    FILE **pipes; 
    char buf[BUFSIZ]; 

    pipes = malloc(((argc - 1) * sizeof *pipes)); 
    if (!pipes) 
     exit(EXIT_FAILURE); 

    for (i = 1; i < argc; i++) { 
     pipes[i - 1] = popen(argv[i], "w"); 
     if (!pipes[i - 1]) { 
      fprintf(stderr, "Can not open pipe to '%s\'\n", argv[i]); 
      close_pipes(pipes, argc); 

      exit(EXIT_FAILURE); 
     } 
    } 
    argc--; 

    while(!feof(stdin) && (!ferror(stdin))) { 
     r = fread(buf, sizeof(char), BUFSIZ, stdin); 
     for(i = 0; i < argc; i++) { 
      if (fwrite(buf, sizeof(char), r, pipes[i]) != r) { 
       fprintf(stderr, "Write error to `%s\'\n", argv[i + 1]); 
       close_pipes(pipes, argc); 
       exit(EXIT_FAILURE); 
      } 
     } 
    } 
    exit(close_pipes(pipes, argc)); 
} 
+0

это сработало. спасибо – luispcosta

+0

'pee' интересен, но это не стандартная установка, вы должны установить его (и иметь возможность установить его). Исходный код интересен, но он не самый лучший, чтобы начать - если цель для @ user3162721 заключалась в том, чтобы что-то узнать? Тогда, может быть, лучше попытаться исправить вышеупомянутый код и объяснить ему, что случилось, - вот что я пытался. – TMS

0

Проблема заключается в том, что потоки могут идти только в один пункт назначения. Вам нужно будет открыть два потока и отправить их каждому пункту назначения, и я не знаю, как это сделать.

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

Для расширения:

в прог 1 - всякий раз, когда она принимает входные данные от стандартного ввода - это, а также обработки он выводит те же данные на стандартный вывод. Это означает, что вы можете добавить его в цепочку broadcast | prog1 | prog2, и данные передаются через prog2, а также обрабатываются prog1.

+0

Не понял ваш ответ: s – luispcosta

+0

Я добавил немного больше, посмотрим, поможет ли это –

1

Это можно легко сделать в скорлупе:

FIFO_FILE=/tmp/fifo$$ 
mkfifo $FIFO_FILE 
cat $FIFO_FILE | prog1 & 
cat | tee $FIFO_FILE | prog2 
wait # wait for everything to finish 
rm -f $FIFO_FILE 

Если вы настаиваете на коде C ... Есть так много проблем, которые я нашел в своем коде:

  • оболванивания другой конец трубы (0 вместо 1)
  • закрыть другую трубку в дочерних процессах
  • вы должны обработать возвращаемое значение read, фактическое количество прочитанных байтов - и pas оно что к write функции
  • вы должны закрыть концы ребенка труб в родительском
  • родителя должен закрыть свои трубы после этого
  • unnecesasry dup2 вызовов в конце программы

Из числа Я вижу, что вы этого не понимаете (извините ...).Но в основном я должен поблагодарить вас - вы создали 2 трубы и цикл while, это ядро ​​программы было почти правильным. Я рекомендую вам начать шаг за шагом на небольших примерах обучения:

Linux Documentation Project - pipes in C

Этот ценный ресурс научит вас, как сделать трубы, как переадресовать и т.д.

Вот моя попытка исправить код:

int main(int argc, char* argv[]) { 
    int fds1[2], fds2[2]; 
    char buffer[120]; 
    int size; 

    pipe(fds1); 
    pipe(fds2); 

    if (fork() == 0) { 
     close(0); 
     dup(fds1[1]); 
     close(fds1[0]); 
     close(fds1[1]); 
     close(fds2[0]); 
     close(fds2[1]); 
     execl(argv[1], argv[1], NULL); 
    } 

    if (fork() == 0) { 
     close(0); 
     dup(fds2[1]); 
     close(fds1[0]); 
     close(fds1[1]); 
     close(fds2[0]); 
     close(fds2[1]); 
     execl(argv[2], argv[2], NULL); 
    } 

    close(fds1[1]); 
    close(fds2[1]); 

    while((size = read(0, buffer, 120)) != 0) { 
     printf("lido: %s\n", buffer); 
     write(fds1[0],buffer,size); 
     write(fds2[0],buffer,size); 
    } 

    close(fds1[0]); 
    close(fds1[0]); 

    exit(0); 
} 

Обратите внимание, что вы должны обрабатывать все системные вызовы, проверяя -1 возвращаемого значения и ERRNO по perror!

+0

Спасибо, но мне действительно нужно это сделать в c-коде xD. +1 для выполнения в shell tho – luispcosta

+0

В двух других программах я должен просто читать с fd 0? Редактировать: Да, это своего рода домашнее задание. – luispcosta

+0

@ user3162721 Да - вот что, когда они получают свой вклад. – TMS

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