查看以下代码:
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
main() {
int pipdes[2];
char buff[50];
const char parent[]="Parent Writes. Child Reads\n";
const char child[]="Child Writes. Parent Reads\n";
if(pipe(pipdes)==0) {
pid_t pid=fork();
if(pid<0)
printf("Error\n");
if(pid==0){
read(pipdes[0],buff,50);
printf("Parent: %s",buff);
write(pipdes[1], child, strlen(child));
exit(0);
}
else if(pid>0) {
write(pipdes[1], parent, strlen(parent));
wait(pid);
read(pipdes[0], buff, 50);
printf("Child: %s", buff);
}
}
else
printf("Error in pipe\n");
}
现在,我在这里创建了一个管道,但这两个进程都可以读写。管道不应该是单向的。 此外,当我把传统的'close(pipdes [0])'用于父级和'close(pipdes [1])'用于子级时,代码不起作用,尽管我添加了open(pipdes [0])函数后面。
我对UNIX和管道的概念仍然是原始的,所以我在这里可能会有点蹩脚,但请你协助。
答案 0 :(得分:18)
在某些系统上,管道可以是双向的。但它们并非必须如此,并且任何假设它们都是不可移植的。特别是,它们不在Linux上。
实际上,您的代码存在问题 - 两个进程都在尝试读取和写入同一个管道。管道的预期用途是孩子写,父母读,反之亦然。你现在正在做的事情目前适用于你,因为你正在阅读和写作一次,wait
对孩子。但是当你在尝试按照你正在做的方式做事时循环,你不能wait
- 如果没有同步,孩子经常(但不总是!)最终会读到它想发送到的内容父母,反之亦然。
如果您希望数据在两个方向上流动,则可以使用两对管道。我们称他们为parent_pipe
和child_pipe
。家长会从parent_pipe[0]
读取并写信给child_pipe[1]
,孩子会从child_pipe[0]
读取并写信给parent_pipe[1]
。
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
int main() {
int parent_pipe[2];
int child_pipe[2];
char buff[50];
if(pipe(parent_pipe) || pipe(child_pipe)) {
perror("pipe(...)");
exit(1);
}
// As noted elsewhere, you're using `fork()` incorrectly.
// `fork()` returns 0 to the child, and a pid to the parent, or -1 if an error
// occurs.
int pid = fork();
if (pid == -1) {
perror("fork()");
exit(1);
}
if (pid == 0) {
// this is the child process. read from child_pipe, write to parent_pipe
const char child[]="Child Writes. Parent Reads\n";
int in, out;
in = child_pipe[0];
// in = parent_pipe[0]; // uncomment me to test with one pipe pair
out = parent_pipe[1];
for (int i = 0; i < 10; ++i) {
read(in,buff,50);
printf("Parent: %s",buff);
// NOTE: `strlen(child)` doesn't include the nul at the end!
write(out, child, strlen(child) + 1);
}
}
else {
// this is the parent process
const char parent[]="Parent Writes. Child Reads\n";
int in, out;
in = parent_pipe[0];
out = child_pipe[1];
// out = parent_pipe[1]; // uncomment me to test with one pipe pair
for (int i = 0; i < 10; ++i) {
write(out, parent, strlen(parent) + 1);
read(in, buff, 50);
printf("Child: %s", buff);
}
}
}
或者,您可以使用由socketpair(AF_LOCAL, SOCK_STREAM, 0, sockdes)
创建的一对UNIX套接字(其中sockdes
是我们重命名为pipdes
的,因为它现在是套接字,而不是管道)。孩子会读取并写入sockdes[0]
,父母会读取并写入sockdes[1]
。反之亦然。
答案 1 :(得分:5)
在POSIX.1-2001中,管道是单向的。从手册页:
pipe()创建一对文件描述符,指向管道inode, 并将它们放在filedes指向的数组中。 filedes [0]适用于 阅读,filedes [1]用于写作。
顺便说一下,您对fork
的使用是错误的:fork
为父级返回pid>0
,为子级返回pid==0
。 pid<0
表示存在错误。
答案 2 :(得分:4)
不,他们不是。有些系统采用双向管道(太阳,IIRC)。如果您确实需要双向管道,可以使用socketpair()。