2013-05-10 62 views
0

我正在尝试使用管道通信来编写程序。这就是我想要做的:用户发送正整数。如果用户发送负号,则通信结束。父进程打印最大数量和最小数量。这是我试过的:Pipe()不能正常工作 - linux

#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); 
} 
} 

这个printf("The parent read %d:",*buff);只打印我给的第一个数字。有人能更好地向我解释我必须做什么吗?如何打印所有缓冲区?我只在缓冲区中写入1个数字,就是这样吗?我如何找到最大最小数字?我很困扰! :(

+0

你需要调用'fflush(NULL)'...,你可以使用'fdopen'(或者'popen') – 2013-05-10 13:02:10

+0

@BasileStarynkevitch在哪里? fflush做了什么? – MathMe 2013-05-10 13:03:27

+1

为了正确性/可移植性,该写入调用应为'write(pfd [1],&n,sizeof(n))'。但是,它不会改变您看到的行为。 – pilcrow 2013-05-10 13:17:10

回答

0

这是一种做我认为你正在尝试做一些修改的方法。 请注意,buff不再是一个数组,我们在打印数字时使用管道本身作为临时存储。

#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); 
    } 
} 
+0

谢谢!我用while循环计算出来。如何找到通信结束后输入的最小和最大数字(我给出一个负数来阻止它? – MathMe 2013-05-10 14:12:19

+0

这是另一个问题......我很确定答案在StackOverflow上,我想你可以有一个最大值和一个最小值,都被初始化为您读取的第一个值,然后在循环中,您可以在每次读取另一个数字时更新它们(如果它大于最大值,则更新最大值,如果较低比最低限度,你更新最低限度)。 – lgeorget 2013-05-10 14:15:15

+0

谢谢。在此期间,我做到了。:) – MathMe 2013-05-10 14:54:56

1

这可能是因为*buff是一个整数,但是你写的不止一个。

如果您想要打印的所有整数发送,那么你需要知道的是有多少转移,然后打印出来在


循环。你也有一个问题,因为你只发送整数(通常为四个字节)的一个字节。您应该使用如

write(pfd[1], &n, sizeof(n)); 
+0

但是如果我只是抛光,我得到一个错误 – MathMe 2013-05-10 13:06:36

+0

@MoldovanRazvan是因为'buff'是一个数组,而你想打印一个整数。您需要在循环中打印,正如我在回答中所述。 – 2013-05-10 13:07:35

1

我相信,你不明白,<stdio.h>函数(如scanffprintf)是生我的不同/ O系统调用像read(2)write(2)(实际上printffprintf可以调用write(2),你可能会迫使他们这样做与fflush

我不明白你想在管道上做什么协议。看起来你想发送原始字节(然后你被限制在0-255)。或者你想发送每个ASCII码的号码,每行一个?

也许你可以做(​​假设协议文本,在ASCII码,每行一个)在父进程

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); 

,并在子进程

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); 
}; 

如果你想只使用低级I/O系统调用(即read(2)write(2)),您必须自己管理缓冲区(因此,请考虑readwrite系统调用的结果,该调用可能是字节读取的部分计数r写)。

不要忘记用gcc -Wall -g(所有警告和调试信息)进行编译,并学习使用gdb进行调试。

+0

这就是为什么。如果你想发送号码1,你需要发送4个字节。因此,不应写入(数组[0],&n,1),它应该读为写(数组[0],&n,4)。在管道的另一端,需要将4个字节读入一个int,然后才能得到正确的数字。如果你发送ascii,你需要使用一个无符号字符,然后在你写入时只发送1个字节。另一方面,你投到一个字符,然后你会有你的ASCII码。您还需要知道要阅读多少内容,否则您将无法知道什么时候停止阅读,并且会阻止等待管道中的信息。 – Magn3s1um 2013-05-10 13:16:01

+0

它应该至少是'write(pdf [1],&n,sizeof(n))',你应该*检查写入的字节数(由'write'返回)。 – 2013-05-10 13:17:21

0
#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); 
    } 
} 
+0

转换为字符串有什么意义?您可以在管道中写入任何内容,它在字节级别运行。 – lgeorget 2013-05-10 14:12:05

+0

@lgeorget'写(pfd [1],n,sizeof(int));'这个工程? – 2013-05-10 14:13:32

+0

是的,它的确如此。从'write(2)':'ssize_t write(int fd,const void * buf,size_t count);'。它需要一个指向'void *'的指针,这意味着它甚至不会查看缓冲区的内容。它只是一个接一个地打印字节。 – lgeorget 2013-05-10 14:17:12

0

write(pfd[1],&n,1); 

只写一个字节。你需要这个:

write(pfd[1],&n, sizeof n); 

这读取无论是在管道缓冲区可用

read(pfd[0],buff,sizeof(buff)); 

它会阻止,直到有东西可以读,然后返回它实际上已经阅读然而,许多字节。可能的顺序是:

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 

你的父母需要继续读书,直到它拥有所有预计的数字或到达文件末尾(通过读取返回0来表示)。事情是这样的:

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 
} 

需要注意的是,从理论上说,你可能甚至不读所有四个字节整型一气呵成,虽然,我认为,在管道的做法,这将不会发生。