2013-03-04 54 views
5

我正在開發C中的應用程序。 父進程和子進程通過管道進行通信。 在寫入管道之前,父進程執行另一個語句。在示例代碼中,我使用睡眠(10)來延遲。 在子進程中,它應該從管道讀取數據。 但是在子進程中管道的讀取端沒有讀取數據。如何等待數據寫入管道的另一端

int main() 
{ 
    int pid; 
    FILE *fp; 
    fp = fopen("test.txt","w"); 
    char *buff; 
    int fd[2]; 
    int count = 0 ; 
    pipe(fd); 
    pid = fork(); 
    if(pid == 0) 
    { 
     close(fd[1]); 
     ioctl(fd[0], FIONREAD, &count); 
     fprintf(fp,"Value of count: %d ",count); 
     buff = malloc(count); 
     fprintf(fp,"\n TIME before read: %s",__TIME__); 
     read(fd[0], buff, count); 
     fprintf(fp,"\nbuffer: %s\n TIME after read %s", buff, __TIME__); 
    } 
    else{ 
     close(fd[0]); 
     sleep(10); //delay caused by application specific code replaced with sleep 
     write(fd[1],"THIS is it",10); 
    } 
    fclose(fp); 
    return 0; 
} 

如何讓子進程等到數據寫在另一端?

回答

5

你管阻塞模式打開,不管你做什麼改變那可能是你想要的。然而,由於你要做的第一件事就是請求等待在管道上的數據的大小,然後盲目地跳到讀取那麼多字節(在代碼執行的時候很可能是零,因爲父節點沒有'不要寫任何東西),你不會阻止,而是因爲你什麼都沒要求而離開。

有很多方法可以做到這一點,包括選擇循環。如果您寧願阻止進行讀取,直到數據可用,那麼在單個字節上執行此操作,然後填寫其餘數據。

這絕不是一個如何做到這一點的例子right,但它是一個很簡單的例子,說明如何在單個字節上等待,請求讀取管道大小以獲得剩餘部分數據,讀取它,並繼續執行此操作,直到管道沒有數據並且父節點關閉它們的末端:

我希望你覺得它有幫助。

#include <stdio.h> 
#include <unistd.h> 
#include <sys/ioctl.h> 

int main() 
{ 
    int pid = 0; 

    // create pipe pair 
    int fd[2]; 
    pipe(fd); 

    pid = fork(); 
    if (pid == 0) 
    { 
     // child side 
     char *buff = NULL; 
     char byte = 0; 
     int count = 0; 

     // close write side. don't need it. 
     close(fd[1]); 

     // read at least one byte from the pipe. 
     while (read(fd[0], &byte, 1) == 1) 
     { 
      if (ioctl(fd[0], FIONREAD, &count) != -1) 
      { 
       fprintf(stdout,"Child: count = %d\n",count); 

       // allocate space for the byte we just read + the rest 
       // of whatever is on the pipe. 
       buff = malloc(count+1); 
       buff[0] = byte; 
       if (read(fd[0], buff+1, count) == count) 
        fprintf(stdout,"Child: received \"%s\"\n", buff); 
       free(buff); 
      } 
      else 
      { // could not read in-size 
       perror("Failed to read input size."); 
      } 
     } 

     // close our side 
     close(fd[0]); 
     fprintf(stdout,"Child: Shutting down.\n"); 
    } 
    else 
    { // close read size. don't need it. 
     const char msg1[] = "Message From Parent"; 
     const char msg2[] = "Another Message From Parent"; 
     close(fd[0]); 
     sleep(5); // simulate process wait 
     fprintf(stdout, "Parent: sending \"%s\"\n", msg1); 
     write(fd[1], msg1, sizeof(msg1)); 
     sleep(5); // simulate process wait 
     fprintf(stdout, "Parent: sending \"%s\"\n", msg2); 
     write(fd[1], msg2, sizeof(msg2)); 
     close(fd[1]); 
     fprintf(stdout,"Parent: Shutting down.\n"); 
    } 
    return 0; 
} 

輸出

Parent: sending "Message From Parent" 
Child: count = 19 
Child: received "Message From Parent" 
Parent: sending "Another Message From Parent" 
Parent: Shutting down. 
Child: count = 27 
Child: received "Another Message From Parent" 
Child: Shutting down. 
1

問題是獲取寫入管道的字節數。你正好在fork()之後得到它。如果讀取過程首先執行,它將不包含數據(並且計數將爲零)。如果寫入過程首先執行,它將包含一些數據。

如何讓子進程等到數據寫在另一端?

由於您在阻塞模式下打開管道,因此應該儘可能多地讀取數據,而不要嘗試獲取寫入數據的大小。


下面是修改後的示例是等待一個完整的消息:

#include <stdio.h> 
#include <sys/ioctl.h> 
int main() 
{ 
int pid; 
FILE *fp; 
fp = fopen("test.txt","w"); 
char *buff = malloc(1024); 
int fd[2]; 
int count = 0 ; 
pipe(fd); 
pid = fork(); 
     if(pid == 0) 
     { 
       close(fd[1]); 

       int i = 0; 

       while (i < 10) 
       { 
        fprintf(fp,"\n TIME before read: %s \n",__TIME__); 
        read(fd[0], buff+i, 1); 
        ++ i; 
       } 

       fprintf(fp,"Full message received!\nbuffer: %s\n TIME after read %s\n", buff, __TIME__); 
     } 
     else{ 
       close(fd[0]); 
       sleep(10); //delay caused by application specific code replaced with sleep 
       write(fd[1],"THIS is it",10); 
     } 
fclose(fp); 
return 0; 
} 
+0

這就是正確的,但是父母每次寫可變大小數據,這就是爲什麼我用ioctl來獲取管道上的數據的大小。我可以阻止ioctl直到在管道上收到數據爲止嗎? – 2013-03-04 08:49:08

+0

@Ajay不,沒有辦法阻止'ioctl()'。 – 2013-03-04 08:51:25

+1

@Ajay老實說,如果大小是重要的我會強烈建議*反對*利用'ioctl()'這個信息。從字面上看,從調用它的時間開始,直到您跟進一個read-op,由於從管道的另一端寫入了更多的數據,大小可能已經無效。如果你想讀取父節點將要發送的num-bytes,那麼把你的*協議的那部分(例如,前四個字節是一個32位網絡字節順序的消息長度)。 – WhozCraig 2013-03-04 08:55:24

1

我想以後

ioctl(fd[0], FIONREAD, &count); 
the count is 0. 

read(fd[0], buff, count) will get no data. 

try 
read(fd[0], buff, 10) 
+0

我已經使用ioctl來確定管道末端數據的大小,因爲父進程發送的數據長度可變。 – 2013-03-04 08:12:17

+0

@Ajay正確,但在您點擊它時,管道中尚無*數據。因此,你最終要求*零*字節,它不會阻塞。 – WhozCraig 2013-03-04 08:28:22

+0

@WhozCraig有什麼辦法可以讓ioctl(xxxx)函數等待,直到管道末端有數據可用,即與read()等待數據可用的方式完全相同。 – 2013-03-04 08:42:28