Reputation: 6192
I'm trying to make two child process to communicate with each other via a pipe.
One child is supposed to keep reading from stdin, passing what it read to the pipe, while the other child is supposed to read from the pipe and print that to stdout.
I manage to get it to work, but only once, in the second iteration after reading a number, I get: write failed: Bad file descriptor
.
I can't figure out what am I doing wrong...
#define READ 0
#define WRITE 1
int main(){
int pipe_descs[2];
int retval = pipe(pipe_descs);
int pid = fork();
if(pid == 0){ //son that reads from stdin and writes to pipe
close(pipe_descs[READ]);
int x;
while(1){
open(pipe_descs[WRITE]);
scanf("%d", &x);
if(write(pipe_descs[WRITE], &x, sizeof(int)) != sizeof(int)){
perror("write failed");
exit(EXIT_FAILURE);
}
close(pipe_descs[WRITE]);
}
perror("");
}
else if(pid > 0){ //parent
int pid = fork();
if(pid == 0){ //son that reads from pipe and write to stdout
int pipestat;
int readNum;
close(pipe_descs[WRITE]);
while((pipestat = read(pipe_descs[READ], &readNum, sizeof(int))) > 0){
printf("read: %d \n", readNum);
//close(pipe_descs[READ]);
//open(pipe_descs[READ]);
}
if (pipestat==-1) {
perror("");
fprintf(stderr, "error to pipe... exiting\n");
exit(EXIT_FAILURE);
}
}
}
int status;
int i = 2;
while (i > 0){
wait(&status);
i--;
}
}
Upvotes: 0
Views: 1926
Reputation: 385839
If you're going to close the writer (close(pipe_descs[WRITE]);
), you can't keep using it! Either remove that statement, or exit the loop after closing the pipe.
open(pipe_descs[WRITE])
makes no sense! Get rid of that.
[If your system complies with POSIX.1-2001, and if the amount you are writing is smaller than PIPE_BUF
, then you can ignore this section.]
write(..., sizeof(int)) != sizeof(int)
doesn't (necessarily) indicate an error condition. If no error occurred, then write
didn't set errno
to something meaningful, so the error message you obtained is meaningless.
Since it's not an error for write
to write less than the requested amount, it needs to be called in the a loop. Replace
if(write(pipe_descs[WRITE], &x, sizeof(int)) != sizeof(int)){
perror("write failed");
exit(EXIT_FAILURE);
}
with
my_write(pipe_descs[WRITE], &x, sizeof(x));
and add
void my_write(int fd, const void *buf, size_t bytes_to_write) {
while (bytes_to_write > 0) {
ssize_t bytes_written = write(fd, buf, bytes_to_write);
if (bytes_written == -1) {
perror("write failed");
exit(EXIT_FAILURE);
}
buf += bytes_written;
bytes_to_write -= bytes_written;
}
}
Similar, it's not an error for read
to return less than the requested amount. As such, it also needs to be called in the a loop. Replace
while((pipestat = read(pipe_descs[READ], &readNum, sizeof(int))) > 0){
printf("read: %d \n", readNum);
//close(pipe_descs[READ]);
//open(pipe_descs[READ]);
}
if (pipestat==-1) {
perror("");
fprintf(stderr, "error to pipe... exiting\n");
exit(EXIT_FAILURE);
}
with
while (my_read(pipe_descs[READ], &readNum, sizeof(readNum))) {
printf("read: %d \n", readNum);
}
and add
int my_read(int fd, void *buf, size_t bytes_to_read) {
int has_read = 0;
while (bytes_to_read > 0) {
ssize_t bytes_read = read(fd, buf, bytes_to_read);
if (bytes_read == -1) {
perror("read failed");
exit(EXIT_FAILURE);
}
if (bytes_read == 0) {
if (has_read) {
fprintf(stderr, "read failed: Premature EOF");
exit(EXIT_FAILURE);
}
return 0;
}
has_read = 1;
buf += bytes_read;
bytes_to_read -= bytes_read;
}
return 1;
}
Upvotes: 2