Reputation: 13
I'm trying to understand how pipes work and it is rather confusing when I was reading this code in my textbook. In the line
dup(fd2[0]); close(fd2[0]);
why are we duplicating fd2[0]
,then close it right after we duplicated it?
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
struct timespec ts1, ts2;
pid_t newpid;
int fd1[2], fd2[2];
char m0[] = "\nabout to fork....\n";
char m1[] = "message from parent to child\n";
char m2[] = "message from child to parent\n";
char m3[] = "\ndone....\n";
char rbuf1[256];
char rbuf2[256];
int cn1, cn2;
ts1.tv_sec=(time_t)1;
ts1.tv_nsec=(long)1;
ts2.tv_sec=(time_t)1;
ts2.tv_nsec=(long)1;
if ((pipe(fd1)==-1)) printf("error\n");
if ((pipe(fd2)==-1)) printf("error\n");
printf("fd1 %d %d fd2 %d %d\n", fd1[0], fd1[1], fd2[0], fd2[1]);
if ((newpid=fork()) ==-1) {
printf("failed to fork\n\n");
return 0;
}
if (newpid > 0) { // parent ***************
close(fd1[1]); close(fd2[0]); // closing 4 and 5
dup(fd2[1]); close(fd2[1]); // taking 4 in place of 6
write(4, m1, sizeof(m1)); // parent_to_child messg
usleep(10000);
cn1=read(3, rbuf1, 256);
write(1, rbuf1, cn1);
} else { // child ***************
close(fd1[0]); close(fd2[1]); // closing 3 and 6
dup(fd2[0]); close(fd2[0]); // taking 3 in place of 5
write(4, m2, sizeof(m2)); // child_to_parent messg
usleep(10000);
cn2=read(3, rbuf2, 256);
write(1, rbuf2, cn2);
}
write(2, m3, sizeof(m3));
return 0;
}
Upvotes: 0
Views: 625
Reputation: 134286
You did not show us your code, however, from the man page of dup()
int dup(int oldfd);
and
dup() uses the lowest-numbered unused descriptor for the new descriptor.
This clearly says, dup()
will return a new file descriptor for oldfd
. you need to assign the return value of dup()
to get the new fd
. Once you get the new fd
, you can close the old fd
and use the newly returned descriptor to access the file.
Once more approach, commonly used, is to close a well-known file descriptor and after that call dup()
which will assign the recently closed fd
as the new fd
. [Example : STDIN_FILENO
]
Upvotes: 1
Reputation: 409136
The usual sequence is to have another close
call before the dup
call, or to assign the result of the dup
and use it.
The first variant is the most common, for example to use the pipe read end as the new STDIN_FILENO
you can do
close(STDIN_FILENO); // Close the current standard input descriptor
dup(pipefds[0]); // Duplicate the pipe read-end, which will become our new standard input
close(pipefds[0); // Close the old pipe descriptor, to save descriptor resources
This will work because dup
will select the lowest available descriptor, which after the first close
call will be STDIN_FILENNO
(descriptor 0
).
And dup
does exactly what it souds like, it duplicates the descriptor, so after a call to dup
you will have two descriptors referencing the same "file", and can freely close one of them.
I suggest you read the the dup(2)
manual page.
Upvotes: 0