2011-05-21 91 views
2

我試圖在使用命名管道的進程之間傳遞結構。我被困在試圖打開管道非阻塞模式。這裏是我的代碼寫入FIFO:在C中讀/寫struct到fifo

void writeUpdate() { 
    // Create fifo for writing updates: 
    strcpy(fifo_write, routing_table->routerName); 
    // Check if fifo exists: 
    if(access(fifo_write, F_OK) == -1) 
     fd_write = mkfifo(fifo_write, 0777); 
    else if(access(fifo_write, F_OK) == 0) { 
     printf("writeUpdate: FIFO %s already exists\n", fifo_write); 
     //fd_write = open(fifo_write, O_WRONLY|O_NONBLOCK); 
    } 
    fd_write = open(fifo_write, O_WRONLY|O_NONBLOCK); 
    if(fd_write < 0) 
     perror("Create fifo error"); 
    else { 
     int num_bytes = write(fd_write, routing_table, sizeof(routing_table)); 
     if(num_bytes == 0) 
      printf("Nothing was written to FIFO %s\n", fifo_write); 
     printf("Wrote %d bytes. Sizeof struct: %d\n", num_bytes,sizeof(routing_table)+1); 
     } 
    close(fd_write); 
    } 

routing_table是指向我的結構,它的分配,所以有與FIFO或不服這樣的名字沒有概率。 如果我在沒有O_NONBLOCK選項的情況下打開fifo,它會第一次寫入smth,但是會阻塞,因爲我也有麻煩讀取結構。第一次之後,最初的fifo被創建,但其他fifo出現,名爲'。','..'。 設置了O_NONBLOCK選項後,它會創建FIFO,但始終會引發錯誤:'沒有這樣的設備或地址'。任何想法爲什麼發生這種情況謝謝。

編輯:好的,所以我現在清楚打開fifo,但我有另一個問題,其實讀/寫結構到fifo是我的問題開始。我的代碼讀取結構:

void readUpdate() { 
struct rttable *updateData; 
allocate(); 

strcpy(fifo_read, routing_table->table[0].router); 

// Check if fifo exists: 
if(access(fifo_read, F_OK) == -1) 
    fd_read = mkfifo(fifo_read, 777); 
else if(access(fifo_read, F_OK) == 0) { 
    printf("ReadUpdate: FIFO %s already exists\n Reading from %s\n", fifo_read, fifo_read);   
} 
fd_read = open(fifo_read, O_RDONLY|O_NONBLOCK); 
int num_bytes = read(fd_read, updateData, sizeof(updateData)); 
close(fd_read); 
if(num_bytes > 0) { 
    if(updateData == NULL) 
     printf("Read data is null: yes"); 
    else 
     printf("Read from fifo: %s %d\n", updateData->routerName, num_bytes); 

    int result = unlink(fifo_read); 
    if(result < 0) 
     perror("Unlink fifo error\n"); 
    else { 
     printf("Unlinking successful for fifo %s\n", fifo_read); 
     printf("Updating table..\n"); 
     //update(updateData); 
     print_table_update(updateData); 
    } 
} else 
    printf("Nothing was read from FIFO %s\n", fifo_read); 
} 

它打開了FIFO和嘗試讀取,但似乎沒有什麼是FIFO中,雖然在writeUpdate第一次它說,它寫了4個字節(這似乎是錯誤太多)。在閱讀時,首次打印'a',然後num_bytes始終爲< = 0。 我環顧四周,只發現這個例子,用簡單的寫/讀,有沒有更需要寫時結構?

我的結構是這樣的:

typedef struct distance_table { 
char dest[20];  //destination network 
char router[20];  // via router.. 
int distance; 
} distance_table; 

typedef struct rttable { 
char routerName[10]; 
char networkName[20]; 
struct distance_table table[50]; 
int nrRouters; 
} rttable; 

struct rttable *routing_table; 

回答

2

「沒有這樣的設備或地址」是ENXIO錯誤消息。如果你看一下open手冊頁,你會看到這個錯誤發生在特定的報告,如果:

O_NONBLOCK | O_WRONLY is set, the named file is a FIFO and no process has the file open for reading. (...)

這正是你的狀況。所以你看到的行爲是正常的:你不能寫入(沒有阻塞)到沒有閱讀器的管道。如果沒有任何東西連接到管道進行讀取,內核將不會緩衝您的消息。

因此,請確保您在「製作人」之前啓動「消費者」,或刪除製作人的非阻止選項。

順便說一句:使用access是在大多數情況下,打開自己time of check to time of use問題。不要使用它。嘗試mkfifo - 如果它有效,你很好。如果它失敗EEXISTS,你也很好。如果失敗,則清理並紓困。

對於問題的第二部分,它完全取決於您嘗試發送的數據的結構。在C中序列化一個隨機結構並不容易,尤其是如果它包含可變數據(例如char * s)。

如果結構只包含基本類型(沒有指針),並且雙方都在同一臺機器上(和相同的編譯器編譯),則原始write一邊和read上之外的整個結構的應該管用。

例如,您可以查看C - Serialization techniques獲取更復雜的數據類型。

關於你的具體例子:你在指向你的結構和普通結構的指針之間混在一起。

寫入側您有:

int num_bytes = write(fd_write, routing_table, sizeof(routing_table)); 

這是不正確,因爲routing_table是一個指針。您需要:

int num_bytes = write(fd_write, routing_table, sizeof(*routing_table)); 
// or sizeof(struct rttable) 

閱讀方面的情況相同。據我所知,在接收大小上,您也沒有分配updateData。你也需要這樣做(與malloc,並記住釋放它)。

struct rttable *updateData = malloc(sizeof(struct rrtable)); 
+0

您的權利,但我將不得不寫結構來說,3-5其他進程,併爲每一個我會打開一個不同的先進先出。如果其中一個'消費者'進程沒有讀取數據,我的整個生產者進程就會掛起。所以我想定期寫入fifo,並以某種方式檢查消費者是否讀取數據。整個目的是模擬路由協議(距離向量),不知道我是否有最好的想法。 – joanna 2011-05-21 09:29:44

+0

當你在'open'上發現錯誤時,你知道沒有消費者,所以寫作沒有意義 - 沒有人會在另一端閱讀。所以你的方法適用於'O_NONBLOCK' - 你知道消費者沒有閱讀。 – Mat 2011-05-21 09:43:56

+1

使用access()也是錯誤的另一個原因,因爲它不一定檢查您的有效權限。 – augustss 2011-05-21 09:46:17