我在做我在标题中所说的话时遇到了很大的麻烦。 基本上,我想要一个程序,比如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 用户输入:Hello
输出是: prog1说:你好! prog2说:你好!
基本上,prog1和prog2只是在fd 0上使用read打印。
答案 0 :(得分:1)
可以在shell中轻松完成:
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代码......我在你的代码中发现了很多问题:
read
的返回值,读取的实际字节数 - 并将其传递给write
函数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
检查perror
返回值和ERRNO来处理所有系统调用!
答案 1 :(得分:0)
问题是流只能到达一个目的地。您需要打开两个流并向每个目的地发送一个流,并且没有简单的方法我知道这样做。
最简单的方法是让prog1只是通过它接收的任何输入并将其发送到它的输出,然后你可以将它添加到链的中间,它对其他进程实际上是不可见的。
扩展:
在prog 1中的 - 每当它在stdin上接收输入时 - 它以及处理它在stdout上输出相同的数据。这意味着您可以将其添加到链broadcast | prog1 | prog2
中,数据将传递到prog2以及由prog1处理。
答案 2 :(得分: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));
}