2014-11-17 51 views
4

我想在PHP中使用命名管道來完成一些IPC。我有一個名爲管道通過如何使用命名管道設置fopen超時

$pipePath = __DIR__ . '/pipe'; 
posix_mkfifo($pipePath, 0600); 

創建有整理一番計算後應寫入該管道另一個進程。我可以等待其完成的東西,如讀取結果:

$result = file_get_contents($pipePath); 

或更詳細的

$in = fopen($pipePath, 'r'); 
$result = fread($in, 8192); 
fclose($in); 

(我已經簡化了第二種方法,在實際的代碼我會檢查是否存在錯誤,在一個循環的情況下運行fread結果> 8192個字節等)

然而,當其他工藝應該結束,我不相信它是成功的,所以我想有一個超時試圖閱讀 結果。等待一段時間後,我想放棄並報告一個錯誤,說它崩潰了,等等。使用這兩種方法,PHP代碼將永久掛起(或長時間等待),以等待某些內容寫入管。具體而言,file_get_contentsfread將掛起。

唯一的解決辦法我能想出是這樣的:

$timeout = 10; //seconds 
for ($i = 0; $i < $timeout; $i++) { 
    $in = @fopen($pipePath, 'rn'); 
    if ($in) break; 
    sleep(1); 
} 
if (!$in) { 
    throw new RuntimeException("The other process did not finish in the allotted time"); 
} 
$result = fread($in, 8192); 
fclose($in); 

它使用無證'n'標誌fopen如在this question的意見之一。它會導致fopen呼叫在阻塞時立即失敗。

不過,我不喜歡這個解決方案有兩個原因:

  1. 它通過檢查管每一秒做不必要的工作。
  2. 如果其他進程中的計算需要1.01秒才能完成,這將等待整整2秒鐘以獲得結果。對於我想要做的一些事情來說,這已經足夠浪費時間了,值得嘗試解決這個問題。

當在一個URL上調用fopen時,我可以添加一個context參數指定一個超時值。但是,這似乎不適用於此,也不設置默認套接字超時。

有沒有更好的方法來做到這一點與管道?如果沒有,我可能會考慮切換到Unix套接字,但這些在其他進程中不太容易支持,所以我寧願不這樣做。

(僅供參考,我只關心Linux的;沒有必要有一些在Windows上運行還是別的,萬一這個問題)

回答

1

我發現做到這一點的一種方式......

首先,我不知道n標誌,這是非常有用的信息!

但是,如果函數阻塞,則函數不正確。它仍然返回一個文件句柄。我們可以使用文件句柄並將其傳遞給stream_select函數,以等待數據可用。

事情是這樣的:

$f=fopen("my.fifo","rn"); 
$r=array($f); 
$w=array(); 
$x=array(); 
stream_select($r,$w,$x,10); 

此代碼等待10秒別人寫FIFO的另一端。

+0

不知道爲什麼我沒有想到使用select。我認爲問題的部分原因是我的問題最初聲稱「fopen」會掛起,但實際上它是懸掛的「fread」。 – Austin