Pipe() doesn't work well - linux

感情迁移 提交于 2019-12-25 01:49:27

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!