如何使用命名管道在fopen上设置超时

时间:2014-11-17 04:05:40

标签: php linux ipc fopen

我正在尝试使用命名管道在PHP中进行一些IPC。我有一个通过

创建的命名管道
$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调用阻塞,它会导致fopen调用立即失败。

但是,我不喜欢这个解决方案有两个原因:

  1. 通过每秒检查一次管道来完成不必要的工作。
  2. 如果其他进程中的计算需要1.01秒才能完成,这将等待整整2秒钟以获得结果。对于我想要做的一些事情,这是浪费时间,值得尝试解决问题。
  3. 在URL上调用{{1}}时,我可以添加指定超时值的上下文参数。但是,这似乎不适用于此,也没有设置默认套接字超时。

    使用管道有更好的方法吗?如果没有,我可能会考虑切换到Unix套接字,但在其他进程中这些并不那么容易支持,所以我宁愿不这样做。

    (仅供参考,我只关心Linux;如果这很重要,不需要在Windows或其他任何东西上运行。)

1 个答案:

答案 0 :(得分:2)

我找到了一种方法来做到这一点......

首先,我不知道n标志,这是非常有用的信息!

但是,如果函数阻塞,则该函数失败并不完全正确。它仍然返回一个文件句柄。我们可以使用文件句柄并将其传递给stream_select函数,以等待数据可用。

这样的事情:

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

此代码等待10秒钟让其他人写入fifo的另一端。