2016-10-24 85 views
1

我試圖模擬呼叫者和使用管道接收器之間的談話。我分叉進程並使父進程成爲接收者,而子進程調用者。IPC使用fork()和管()

下面是代碼:

#include <stdio.h> 
#include <string.h> 
#include <stdbool.h> 
#include <sys/types.h> 
#include <unistd.h> 

#define BUF_LEN 25 
#define READ_END 0 
#define WRITE_END 1 

int main() 
{ 
    int fd[2]; 
    if (pipe(fd) == -1) { 
     fprintf(stderr, "Pipe failed"); 
     return 1; 
    } 

    pid_t pid = fork(); 

    if (pid < 0) { 
     fprintf(stderr, "Fork failed"); 
     return 1; 
    } 

    // the parent process is the receiver 
    if (pid > 0) { 
     close(fd[WRITE_END]); 
     char buffer[BUF_LEN + 1] = ""; 
     do { 
      read(fd[READ_END], buffer, sizeof buffer); 
      if (strcmp(buffer, "")) { 
       printf("Received %s\n", buffer); 
      } 
      strcpy(buffer, ""); 
     } while (strcmp(buffer, "Bye!")); 
     close(fd[READ_END]); 
    } else { 
     close(fd[READ_END]); 
     // const char *msg = "Hello"; 
     char buffer[BUF_LEN + 1] = ""; 
     bool end_call = false; 
     do { 
      printf("Caller: "); 
      fgets(buffer, sizeof buffer, stdin); 
      if (strcmp(buffer, "Bye!")) { 
       end_call = true; 
      } 
      // printf("Sent %s\n", buffer); 
      write(fd[WRITE_END], buffer, strlen(buffer) + 1); 
     } while (!end_call); 
     close(fd[WRITE_END]); 
    } 
    return 0; 
} 

但是當我運行它,我得到這個意外的輸出:

Caller: Hi 
Received Hi 

HI 
Hello 
Bye! 
^C 

接收器停止工作,但沒有收到我給的輸入。另外還有額外的換行符出現在輸出中。爲什麼會發生這種情況?

編輯: 正如Dmitri指出的那樣,我改變了調用者的strcmp測試和接收者的printf語句。

#include <stdio.h> 
#include <string.h> 
#include <stdbool.h> 
#include <sys/types.h> 
#include <unistd.h> 

#define BUF_LEN 25 
#define READ_END 0 
#define WRITE_END 1 

int main() 
{ 
    int fd[2]; 
    if (pipe(fd) == -1) { 
     fprintf(stderr, "Pipe failed"); return 1; } 

    pid_t pid = fork(); 

    if (pid < 0) { 
     fprintf(stderr, "Fork failed"); 
     return 1; 
    } 

    // the parent process is the receiver 
    if (pid > 0) { 
     close(fd[WRITE_END]); 
     char buffer[BUF_LEN + 1] = ""; 
     do { 
      read(fd[READ_END], buffer, sizeof buffer); 
      if (strcmp(buffer, "")) { 
       printf("Received %s", buffer); 
      } 
      strcpy(buffer, ""); 
     } while (strcmp(buffer, "Bye!")); 
     close(fd[READ_END]); 
    } else { 
     close(fd[READ_END]); 
     // const char *msg = "Hello"; 
     char buffer[BUF_LEN + 1] = ""; 
     bool end_call = false; 
     do { 
      printf("Caller: "); 
      fgets(buffer, sizeof buffer, stdin); 
      if (!strcmp(buffer, "Bye!")) { 
       end_call = true; 
      } 
      // printf("Sent %s\n", buffer); 
      write(fd[WRITE_END], buffer, strlen(buffer) + 1); 
     } while (!end_call); 
     close(fd[WRITE_END]); 
    } 
    return 0; 
} 

但收到「再見!」後仍不退出。

Caller: hi 
Received hi 
Caller: Hello 
Received Hello 
Caller: Bye! 
Received Bye! 
Caller: Bye! 
Received Bye! 
Caller: ^C 
+1

如果緩衝區足夠大,'fgets()'包含行尾的換行符。 – Dmitri

+1

另外,如果'buffer' *不包含''Bye!',那麼你將'end_call'設置爲'true''' – Dmitri

+0

@Dmitri:ok,但是爲​​什麼它不是在第一條消息之後退出? – In78

回答

2

的strcmp()的成功返回0。但也有其他的一些問題與您的代碼:

  1. 該字符串將永遠不等於「再見!」,也將是表示字符串的結束連接以及空字符新行(共6個字符)。

  2. 管道使用流而不是「數據包」,你永遠不知道你將從一次調用read()中得到多少字節。這可能是不完整的字符串,或者將數據發送速度非常快,你可能會得到2串相互粘結。您需要實現自己的「協議」來解析數據流中的數據。

  3. 如果管子的另一端關閉您還沒有檢查(讀將返回0)

  4. 你得到的輸出額外的新行,因爲它連接到通過fgets()的字符串

  5. 輸出可能會混亂,因爲當進程刷新到標準輸出時,你無法控制(排序條件,但不會崩潰)。
1

將客戶端中的測試更改爲以下內容。這將讓孩子/父母溝通。

if (!strcmp(buffer, "Bye!")) { 

客戶端有換行符在它讀取緩衝區(「再見!」一個換行符以下)。這不符合退出測試。你可以嘗試刪除它。

fgets(buffer, sizeof buffer, stdin); 
    buffer[strlen(buffer)-1]='\0'; 

在服務器端,不要初始化緩衝區(就在while-check之前)。因爲這會重新初始化您要檢查的字符串。

 strcpy(buffer, ""); 

如果你願意,你可以把你運行read功能之前。

您也可能會遇到其他答案指出的問題緩衝問題(匹配結束條件)和競爭條件(關閉fds)。但是,我想這僅僅是「學習」的好例子。祝你好運。

1

,因爲你需要測試的退出條件爲Bye!\nfgets捕獲的換行符其中包括換行符。 strcmp(buffer, "Bye!\n")

這是除固定否定問題的@blackpen指出。

1

您的程序有幾個問題。

首先,當fgets()讀取一行時,包含最後的換行符(如果緩衝區中有足夠的空間)。你看到的額外的換行符是因爲你發送的字符串包含一個,然後當你在接收器中打印時添加另一個。此外,你正在尋找字符串,"Bye!"來決定何時退出......但你實際得到的字符串是"Bye!\n"。您需要從發件人的stdin中讀取的字符串的末尾去掉換行符,或者在打印時以及在比較中考慮換行符中已存在的換行符。

其次,在發件人,你必須檢查何時退出時,你的邏輯倒:您正在設定end_call = true;buffer包含的,而不是當它"Bye!"。這會導致發送者在發送第一個字符串而不是循環後退出(另外,如上所述,需要修正比較以考慮換行符)。它不是早期停止的接收器,它是發送者......接收器由於下一個問題而永遠運行。

在接收器中,您將在循環結束時清除緩衝區,之前您在迴路測試中檢查"Bye!"。這可以防止循環測試中的比較找到匹配,因此循環是無限的。改爲在fgets()之前清除循環開始處的緩衝區。 (再次,修正比較以考慮最後的換行符)。