用QSocket來操作Linux命名管道

  今天使用QSocket來操作命名管道時出現了一些小插曲,調試花了一些時間,寫下來作一個筆記:

  這裏所說的命名管道是指FIFO,當打開一個FIFO的時候,通常會出現以下情況:
  a. 不使用O_NONBLOCK標誌時,只讀open要阻塞到某個其它進程爲寫而打開它爲止
  b. 不使用O_NONBLOCK標誌時,只寫open要阻塞到某個其它進程爲讀而打開它爲止
  c. 如果在open的時候指定O_NONBLOCK標誌,當只讀open時,沒有進程爲寫而打開FIFO的話,會返回-1,只寫open時,沒有進程爲讀而打開FIFO的話也會返回-1表示失敗。

  以上的情況使FIFO的使用帶來了一些不便,但有一個常用的技巧是,只要用O_RDWR(讀寫)來打開一個管道,則不會返回失敗,而open也不會阻塞。兩個進程使用FIFO來進行通信時,通常會使用兩個FIFO,一個用於發送數據(即進行寫操作),一個用於接收數據(即進行讀操作),而這兩個FIFO需要均使用O_RDWR來打開。使用系統調用open, read, write來操作這兩個FIFO沒有什麼問題,程序工作得很好,

  由於項目需要,管道的另一個讀寫端位於Qt上的一個應用程序,因此可以方便地使用QSocket來操作管道,
以寫管道爲例,  我使用了以下步驟:

  1. 先用O_RDWR標誌用open系統調用打開管道,並得到一個fd
  2. new一個QSocket對象, 暫且命名爲 pSocket
  3. 把fd賦給此QSocket對象, 調用 pSocket->setSocket( fd );
  4. 現在可以調用 pSocket->writeBlock 往管道中寫數據了

  測試時發現, 只有第一個pSocket->writeBlock 調用往管道寫數據時, 對端能收到, 其它的多次調用, 對端均收不到使用pSocket->writeBlock寫的數據。

  難道是寫一次後,某些狀態被改變了才導致後面的寫操作失敗?  檢查pSocket->writeBlock 的返回值,是正常的,返回了寫數據的數目而非-1;再用pSocket->state()檢查當前的狀態,返回Connection,也是正常的啊;連接QSocket的bytesWritten信號,也能正常是返回寫了多少字節。

  情況貌似一切正常啊,但對端就是收不到數據,可能是數據在緩衝區中沒發出去?調用一下flush,於事無補,情況依舊,難道是對端的程序設計的有問題?作了個試驗,不使用QSocket往FIFO寫數據,改爲使用系統調用write來寫,結果一切正常,而以之前也有對對端作過測試的,所以排除了是對端程序設計有問題。

  回顧了一下整個過程,再看了一個QSocket的文檔,QSocket是帶緩衝的,也就是說,當我們用QSocket往FIFO寫數據時,QSocket會先將你的數據緩衝起來,當FIFO有數據可讀時,QSocket也會把數據接收並緩衝起來,等待我們去讀取它...停,我們是用O_RDWR會打開FIFO的,會不會是當我們用QSocket往FIFO寫數據時,緊接着QSocket自已又把它讀走,而導致其它進程讀不到數據了呢?

  趕緊connect信號readyRead看看,果然,在我們調用writeBlock後,緊接着readyRead被觸發了,真相大白,是QSocket自已把數據又讀走了。

  最後,解決的辦法也很簡單,當需要用QSocket用操作FIFO時,就不要用O_RDWR來打開FIFO, 而是,在打開讀FIFO時使用只讀打開,而打開寫FIFO時使用只寫打開,爲了FIFO在其它進程沒有就緒的情況下,open不至於阻塞,還需要加上_NONBLOCK標誌。

-------------------------------------------------------------------------------------------------------------------------------------------------------
  轉載請註明出處: http://www.tzsblog.com

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章