2011-05-21 89 views
0

我正在製作一個非常簡單的程序,它由客戶端和服務器進程使用的一個小型API組成。客戶端進程和服務器進程通過一對FIFO進行通信(一個向服務器發送請求,另一個向服務器發送響應)。無法同步阻止讀取和寫入FIFO

  • 服務器不斷讀取請求FIFO與封閉讀取(O_RDWR標誌)
  • 客戶寫FIFO(O_WRONLY標誌)
  • 服務器讀取請求的請求的請求時,它適用於並在響應FIFO(O_WRONLY標誌)上寫入響應
  • 客戶端讀取響應(O_RDONLY標誌):如果服務器沒有傳送任何數據(我的意思是一個未定義的長緩衝區),則寫入的響應先進先出足夠了,工作完成
  • 其他...
  • 的客戶端服務器將要發送的數據的響應讀取,所以它打開的答覆再次FIFO(O_RDONLY標誌)
  • 服務器(O_WRONLY標誌)

最後寫沒有按寫入數據在客戶閱讀另一面之前,似乎不會阻止服務器進程:爲什麼?我錯過了什麼? 爲了實現我的目標,我必須在寫入調用之前先進行睡眠(1),但這僅適用於對服務器的某種請求:我該如何幫助您來幫助我?

服務器代碼

   /* until here everything is ok: client read the response and waits for the buffer */ 
       sleep(1); 
       /* open the FIFO and send the buffer */ 
       if((fifofrom = open(FIFOFROMMMBOXD, O_WRONLY)) == -1) logMmboxd("error in opening FIFOFROM again for the buffer\n", 1); 
       else             logMmboxd("opened FIFOFROM again for the buffer\n", 0); 

       if((write(fifofrom, mails, sizeof(mmbox_mail_complete)*m)) != sizeof(mmbox_mail_complete)*m) logMmboxd("error in writing FIFOFROM again for the buffer\n", 1); 
       else                       logMmboxd("written on FIFOFROM again for the buffer\n", 0);  
       close(fifofrom); 

       logMmboxd("messages list definitely sent\n", 0); 

客戶端代碼

void lockUp(Request *request, Response *response, void **buffer) 
{ 
int fifofrom, fifoto, lock;  

/* lockto access the FIFOs */ 
if((lock = open(LOCK, O_RDONLY)) == -1) logMmboxman("error in opening LOCK\n", 1); 
else          logMmboxman("opened LOCK\n", 0); 

if(flock(lock, LOCK_EX) == -1)   logMmboxman("error in acquiring LOCK\n", 1);    
else          logMmboxman("acquired LOCK\n", 0); 

/* open the FIFO and write the request */ 
if((fifoto = open(FIFOTOMMBOXD, O_WRONLY)) == -1) logMmboxman("error in opening FIFOTO\n", 1); 
else            logMmboxman("opened FIFOTO\n", 0); 

if((write(fifoto, request, sizeof(Request))) != sizeof(Request)) logMmboxman("error in writing FIFOTO\n", 1); 
else                logMmboxman("written on FIFOTO\n", 0); 
close(fifoto); 

/* waiting for response on FIFOFROM */ 
if((fifofrom = open(FIFOFROMMMBOXD, O_RDONLY)) == -1) logMmboxman("error in opening FIFOFROM\n", 1); 
else             logMmboxman("opened FIFOFROM\n", 0); 

if((read(fifofrom, response, sizeof(Response))) != sizeof(Response)) logMmboxman("error in reading FIFOFROM\n", 1); 
else                 logMmboxman("read from FIFOFROM\n", 0); 
close(fifofrom); 

/* if size>0 then the server has to send a buffer of data to me! */ 
if(response->size) 
{ 
    if((fifofrom = open(FIFOFROMMMBOXD, O_RDONLY)) == -1) logMmboxman("error in opening FIFOFROM again for the buffer\n", 1); 
    else             logMmboxman("opened FIFOFROM again for the buffer\n", 0); 

    *buffer = (void*)malloc(response->size); 

    if(read(fifofrom, *buffer, response->size) != response->size) logMmboxman("error in reading FIFOFROM again for the buffer\n", 1); 
    else               logMmboxman("read from FIFOFROM again for the buffer\n", 0); 
    close(fifofrom);  
} 

/* read the response: I release the lock */ 
if(flock(lock, LOCK_UN) == -1)   logMmboxman("error in releasing LOCK\n", 1);    
else          logMmboxman("released LOCK\n", 0); 

return; 
} 
+0

請發表編碼。根據你的描述不可能修復。 – Hogan 2011-05-21 13:43:43

+0

好的,我發佈了一些代碼:) – 2011-05-21 13:46:54

+0

我懷疑在這個應用程序中使用UNIX域套接字而不是FIFO會好得多。首先,它們是雙向的。 – caf 2011-05-23 06:53:52

回答

0

所以(1)你對FIFO的同步推理是正確的; (2)有一個近乎零的機會linux搞砸了;所以(3)你有一個錯誤。

很難說,但是由於您最初開放服務器的fifo爲O_RDWR,也許您沒有完成您的想法?也許你有第二個客戶端運行,已經有該fifo打開作爲一個讀者,當你重新打開O_WRONLY它不會阻止?

無論如何,你真正的問題是你設計的協議。您不需要我可以看到需要鎖定或保持打開和關閉fifo。你需要一個明智的通信協議。

通常,這是一樣的東西:

(1)服務器有一個衆所周知的FIFO客戶端開放和寫入。 (2)客戶端傳遞事務代碼或某事指示這是最初的請求。包括服務器建立連接返回到客戶端的一些方法。這可能是一個完整的路徑名,或者只是一個客戶端和服務器使用預定義路徑創建第二個fifo的pid(例如,打開「/ tmp/myfifo_pid」或其他)。 (3)客戶端&服務器打開第二個fifo後,所有進一步的客戶端請求到服務器包括pid(或其他),以便服務器知道在哪裏輸出請求。

(4)完成之後,客戶端發送一個事務指示,以便服務器可以關閉第二個FIFO。客戶端也一樣。

(5)對於許多客戶重複。

請注意,您需要爲消息指定格式。時間優先的技術是使用長度碼(似乎是你正在嘗試的)或某種類型的msg分隔符(例如換行符)。

編輯

可能的消息格式:

長度| TRANCODE ||數據|

其中長度告訴您有多少個後續字節組成整個消息,轉碼指定和操作(例如,打開我的輸出fifo,關閉它,發送數據,無論什麼),並且數據適合於事務處理。

+0

鴨我會關閉FIFO。我使用O_RDWR標誌,因此我可以繼續循環阻塞讀取:如果我只使用O_RDWR,如果沒有進程在另一端寫入,則讀取不會阻塞,並且正在等待。不可能的:1)我只是在客戶端2上測試它)訪問FIFO鏈,你必須獲得適當的鎖。此外,先進先出隊列是衆所周知的名稱。格式化郵件意味着什麼? – 2011-05-21 17:50:03

+1

@ hysoka44 - 你太過複雜了。最好是讓最簡單的基本案例(服務器/ 1客戶端)先工作,然後從中反覆改進。忘記現在鎖定和鎖永遠。集中精力設計,檢查返回/錯誤代碼,以及在無法讀取/寫入一條消息(例如,請參閱讀/寫的返回代碼)時發生的情況。一旦你有基本的情況下工作,其餘的人會照顧自己。 – Duck 2011-05-21 18:55:14

+0

+1對於您有一個錯誤 – 2011-05-21 19:10:30