问题
I'm trying to make a program using the pipe communication. This is what I'm trying to do: the user sends positive integers. If the user sends a negative number the communication ends. The parent process prints the maximum number and the minimum number. This is what I tried:
#include <unistd.h>
#include <stdio.h>
main(){
int pfd[2];
int buff[200];
pipe(pfd);
if(fork()==0){
close(pfd[0]);
int n;
printf("Give a number: ");
scanf("%d",&n);
while(n >=0 ){
write(pfd[1],&n,1);
printf("Give a number: ");
scanf("%d",&n);
}
exit(0);
}
else{
close(pfd[1]);
read(pfd[0],buff,sizeof(buff));
printf("The parent read %d:",*buff);
wait(0);
}
}
This printf("The parent read %d:",*buff);
prints only the first number I gave. Can someone explain to me better what I have to do? How to print all the buffer? Am I writing only 1 number in the buffer and that's it? How do I find the maximum and the minimum number? I am very confused! :(
回答1:
This is a way to do what I think you're trying to do with a very few modifications.
Notice that buff
is no longer an array and that we use the pipe itself as temporary storage as we print the numbers.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int pfd[2];
int buff;
int max,min;
pipe(pfd);
if(fork()==0){
close(pfd[0]);
int n;
printf("Give a number: ");
scanf("%d",&n);
while(n >=0 ){
write(pfd[1],&n,sizeof(n));
printf("Give a number: ");
scanf("%d",&n);
}
exit(0);
}
else {
close(pfd[1]);
printf("The parent read ");
if (read(pfd[0],&buff,sizeof(int))) {
max = buff;
min = buff;
printf("%d",buff);
}
while (read(pfd[0],&buff,sizeof(int))) {
if (buff > max)
max = buff;
else if (buff < min)
min = buff;
printf("%d:",buff);
}
printf("\n");
printf("The maximum value is: %d.\n The minimum value is: %d.\n",max,min);
wait(NULL);
}
}
回答2:
It might be because *buff
is a single integer, but you wrote more than one.
If you want to print all integers sent, then you need to know how many was transfered, and then print them in a loop.
You also have a problem because you only send one byte of the integer (which is normally four bytes). You should use e.g.
write(pfd[1], &n, sizeof(n));
回答3:
I believe that you don't understand that <stdio.h>
functions (like scanf
and fprintf
) are different of raw I/O syscalls like read(2) and write(2)
(actually printf
and fprintf
can call write(2)
and you may force them to do that with fflush
)
I don't understand what is the protocol you are wanting on the pipe. It seems that you want to send raw bytes (then you are restricted to 0-255). Or do you want to send each number in ASCII, one per line?
Perhaps you could do (assuming the protocol is textual, numbers in ASCII, one per line) in the parent process
FILE* wp = fdopen(pfd[1],"w");
if (!wp) { perror("fdopen wp"); exit(EXIT_FAILURE); };
int num = -1;
do {
num = 0;
printf("Enter a number:\n");
fflush(NULL);
if (scanf(" %d", &num)<=0) break;
fprintf (wp, "%d\n", num);
} while (num>=0 && !feof(stdin));
fclose(wp);
and in the child process
FILE* rp = fdopen(pfd[0], "r");
if (!rp) { perror("fdopen rp"); exit(EXIT_FAILURE); };
while (!feof(rp)) {
int rnum = -1;
fflush(NULL);
if (fscanf(" %d", &rnum)<=0) break;
printf ("parent has read %d\n", rnum);
};
If you want to use only low-level I/O syscalls (i.e. read(2)
and write(2)
) you have to manage buffering by yourself (so, take into account the result of read
and write
syscalls, which may be a partial count of bytes read or written).
Don't forget to compile with gcc -Wall -g
(all warnings and debugging information) and learn to use gdb
for debugging.
回答4:
This
write(pfd[1],&n,1);
only writes one byte. You need this:
write(pfd[1],&n, sizeof n);
This reads whatever is available in the pipe buffer
read(pfd[0],buff,sizeof(buff));
It blocks until there is something to read and then returns however many bytes it actually has read. The likely sequence is:
child writes your first number (probably 4 bytes)
parent reads the first number
parent executes the wait() sys call
you type in the second number (assume its negative)
child writes the second number
child exits
parent exits
Your parent needs to keep reading until it has all the numbers it expects or end of file is reached (signified by read returning 0). Something like this:
int bytesRead;
while ((bytesRead = read(pfd[0], buff, sizeof buff)) > 0)
{
// Do whatever it is you want to do with the bytes
}
if (bytesRead == -1)
{
// report the error
}
Note that, theoretically, you might not even read all four bytes of the int in one go, although, I think, in practice with pipes, this won't happen.
回答5:
#include <unistd.h>
#include <stdio.h>
main(){
int pfd[2];
int buff[200];
pipe(pfd);
if(fork()==0){
close(pfd[0]);
int n;
printf("Give a number: ");
scanf("%d",&n);
while(n >=0 ){
printf("Give a number: ");
scanf("%d",&n);
write(pfd[1],&n,sizeof(int));
}
exit(0);
}
else{
close(pfd[1]);
/* loop ??*/
read(pfd[0],buff,199);
printf("The parent read %d:",buff);
/* loop ??*/
wait(NULL);
}
}
来源:https://stackoverflow.com/questions/16482874/pipe-doesnt-work-well-linux