2016-05-29 112 views
0

我想創建一個命名管道(FIFO)的簡單例子。在這裏,服務器將監聽來自客戶端的消息,該消息寫在命名管道上,這兩者通用。要實施的特殊事項是FIFO應該是非阻塞的(使用O_NONBLOCK)。Linux:創建一個簡單的非阻塞服務器和客戶端通過命名管道進行通信

通過非阻塞,我的意思是作者應該在寫完後立即返回,如果沒有讀者的話。同樣,如果沒有消息(沒有作者),讀者應該立即返回。

我已經創建了阻塞版本,雖然它的工作正常。然後我試圖將其轉換爲非阻塞。

這裏的客戶端:

#include <stdio.h> 
#include <stdlib.h> 
#include <fcntl.h> 

#define FIFO "/tmp/myFIFO" 

/* 
    This acts as the client, writing to the FIFO 
*/ 

int main(int argc, char *argv[]) 
{ 
    FILE *fp; 
    int fifo_fd; 

    if(argc != 2) 
    { 
     printf("Usage : ./fifo_client <message> \n"); 
     exit(1); 
    } 

    fifo_fd = open(FIFO, O_WRONLY | O_NONBLOCK); 
    if(fifo_fd < 0) 
    { 
     perror("Error while open call"); 
     exit(1); 
    } 
    fp = fdopen(fifo_fd, "w"); 
    if(fp == NULL) 
    { 
     perror("Error while opening fd"); 
     exit(1); 
    } 

    fputs(argv[1],fp); 

    /* Close the fp */ 
    fclose(fp); 
    return 0; 
} 

這裏的服務器:

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <fcntl.h> 

#define FIFO "/tmp/myFIFO" 

/* 
    This acts as a server waiting for strings to be written by the client, over the FIFO 
*/ 

int main() 
{ 
    FILE *fp; 
    int fifo_fd; 
    char buf[1024]; 

    /* Create a FIFO */ 
    umask(0); 
    if(mkfifo(FIFO,0666) < 0) /* 0666 is read and write permission*/ 
    { 
     perror("Error creating FIFO"); 
     exit(1); 
    } 


    while(1) /*endless wait, keep reading strings and print*/ 
    { 
     fifo_fd = open(FIFO, O_RDONLY | O_NONBLOCK); 
     if(fifo_fd < 0) 
     { 
      perror("Error while open call"); 
      exit(1); 
     } 
     fp = fdopen(fifo_fd, "w"); 
     if(fp == NULL) 
     { 
      perror("Error while opening fd"); 
      exit(1); 
     } 

     if(!fgets(buf,1024,fp)) 
      printf("Nothing to read\n"); 
     else 
      printf("Message Recieved : %s\n", buf); 
    fclose(fp); 
    sleep(1); 
    } 

    return 0; 
} 

我第一次運行該服務器。

其次,第二終端上,當我運行客戶端,我得到的錯誤:

Error while open call: No such device or address 

我缺少什麼?我做了man,參數看起來是正確的。

編輯

移動openclose召喚出while循環的,做的工作。但是,現在如果客戶端不啓動服務器啓動,引發以下錯誤:

錯誤而公開呼籲:沒有這樣的設備或地址

文件/tmp/myFIFO存在文件系統從服務器的前一次執行,必須由客戶使用。

+0

(與您的問題無關的評論)。如果調用沒有參數的程序來獲得使用語句不是錯誤,你應該'退出0'。如果出現錯誤,您應該將使用說明打印到stderr。 'perror(FIFO)'比'perror(「創建FIFO的錯誤)'更有用。用戶希望在錯誤消息中看到文件的名稱。 –

+0

您不檢查由fgets和fputs返回的錯誤,這意味着您不在乎它們是否成功。爲什麼抱怨你的程序無法正常工作? –

+0

您的服務器重複打印顯示它不是*阻塞。您沒有收到提示,因爲服務器沒有完成。 –

回答

0

主要問題是打開和關閉循環中的文件。這沒有意義。開始和結束之間的時間間隔非常短,您的客戶必須打開它。它幾乎沒有機會這樣做。 「沒有這樣的設備或地址」消息正好發生,因爲客戶端在文件打開時錯過了這個瞬間。這是主要問題。嘗試將open,fopenfclose移出服務器環路。

你也open ing閱讀,但fopen ing爲寫作,但我想這只是一個錯字。這種組合不會運行。您需要將fopen的模式更改爲"r"

還有其他更小的問題。

  1. 您不檢查客戶端中的錯誤。在你的程序中,大部分時間客戶端將無法運行open,但有時候打開會成功,寫入會失敗。
  2. 在此程序中使用stdio作爲管道是沒有意義的。 readwrite會做得很好。

最後但並非最不重要的是,sleep表示設計問題。事實上,在這個程序中,阻止I/O會更有意義。如果您只想嘗試使用非阻塞I/O,則可以使用sleep,但在實際的程序中應該避免。

+0

'你也開放閱讀,但開始寫作,但我想這只是一個錯字.'。不,我故意這樣做,不知道這個組合不起作用的事實。爲什麼這樣?你能否提供理由? –

+0

只要將'open'和'close'呼叫移出'while'循環即可完成這項工作。 「open」和「fopen」的組合沒有問題。但是我沒有得到,爲什麼在循環中放置「open」和「close」調用會產生問題?該文件已經創建...所以第二個過程應該能夠隨時打開並寫入。它是否與讀寫鎖相關? –

+0

@InsaneCoder這是如何指定非阻塞FIFO工作。該文件必須打開才能閱讀,否則打開寫入將失敗。阻塞IO會阻塞。 –

相關問題