-------------------------------------------------------------------------------
From: subbarao@phoenix.Princeton.EDU (Kartik Subbarao)
Newsgroups: comp.unix.programmer
Subject: Re: a pipe problem
pjunold@daimi.aau.dk (Peter Joachim Unold) writes:
>I have a program that starts a process A which sends data to it's child B by
>a pipe. Process A reads it's input from filedescriptor 0. However sometimes
>I want Process B to send data to it's parrent A. It's important that this data
>also should be be read from the same fd as used for stdin. Here's how it looks:
>
>what I'm really trying to do is to make a pipe that looks like:
>
>keyboard->--|
> ------->-----parent
>child---->--|
>
>Is this possible at all? I've tried various variants of pipe, close and dup
>without finding a solution. I hope someone can help me out of this one.
It's not as "easy" as you might like. Writing to file descriptor 0 does not
write to the "read" end of the terminal. To similate keyboard input, you
have to use something like the TIOCSTI ioctl(). But that's a kludge. I'd
rather explain a cleaner way to do it right from your diagram.
What you want to do is to have the parent be able to read from 2 different
file descriptors: 0, and the read end of a pipe that the child writes to.
To simplify things, instead of making 2 pipes, one that the parent writes
to and the child reads from, and another that the child writes to and the
parent reads from, let's simply create a socketpair. socketpair() gives us
2 connected sockets that can be either written to or read from. If I write
to s[0], I can read what I just wrote in s[1]. Likewise, if I wrote to
s[1], I can read what I just wrote in s[0].
Now, the picture is like this:
keyboard----->[parent][child]
socketpair
At any time, the parent could get input from either the keyboard or the
socketpair. We need to use select() to multiplex between the two.
Here's some sample code that does this, with no error checking:
# include
# include
# include
main()
{
int n, s[2], maxfds;
fd_set fdset;
char buf[1024];
maxfds = getdtablesize();
socketpair(PF_UNIX, SOCK_STREAM, 0, s);
FD_ZERO(&fdset); /* initialize the set to be empty */
if (! fork()) { /* child */
sleep(2);
write(s[1], "foo\n", 4); sleep(2);
write(s[1], "zoof\n", 5); sleep(3);
write(s[1], "test\n", 5);
exit(0);
}
while (1) {
FD_SET(0, &fdset); FD_SET(s[0], &fdset);
/* set the file descriptors that we want to check */
select(maxfds, &fdset, NULL, NULL, NULL);
if (FD_ISSET(0, &fdset)) { /* something from tty */
n = read(0, buf, sizeof buf);
write(1, buf, n);
}
if (FD_ISSET(s[0], &fdset)) { /* something from socket */
n = read(s[0], buf, sizeof buf);
write(1, buf, n);
}
}
}
-------------------------------------------------------------------------------