Aren't pipes in UNIX supposed to be uni-directional?
On some systems, pipes can be bidirectional. But they don't have to be, and any assumption that they will be is non-portable. In particular, they aren't on Linux.
As it is, your code has a problem -- both processes are trying to read from and write to the same pipe. The intended use for pipes is that the child writes and the parent reads, or vice versa. The current way you're doing things works for you right now, because you're reading and writing once and wait
ing on the child. But when you loop while trying to do things the way you're doing, you can't wait
-- and without synchronization, the child will often (but not always!) end up reading what it intended to send to the parent, and vice versa.
If you want data flowing in both directions, you could use two pairs of pipes. Let's call them parent_pipe
and child_pipe
. The parent would read from parent_pipe[0]
and write to child_pipe[1]
, and the child would read from child_pipe[0]
and write to 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);
}
}
}
Alternatively, you could use a pair of UNIX sockets created with socketpair(AF_LOCAL, SOCK_STREAM, 0, sockdes)
(where sockdes
is what we renamed pipdes
to, since it's sockets now and not pipes). The child would read from and write to sockdes[0]
, and the parent would read from and write to sockdes[1]
. Or vice versa.
In POSIX.1-2001, pipes are unidirectional. From the man page:
pipe() creates a pair of file descriptors, pointing to a pipe inode, and places them in the array pointed to by filedes. filedes[0] is for reading, filedes[1] is for writing.
By the way, your use of fork
is wrong: fork
returns pid>0
for the parent and pid==0
for the child. pid<0
means there was an error.
No they aren't. There have been some systems with bidirectional pipes (sun, IIRC). If you really need a bidirectional pipe, you could use socketpair().