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

Php 如何使用命名管道在fopen上设置超时,php,linux,ipc,fopen,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);

我正在尝试使用命名管道在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\u-get\u-contents
fread
将挂起

我能想出的唯一解决办法是这样的:

$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);
$f=fopen("my.fifo","rn");
$r=array($f);
$w=array();
$x=array();
stream_select($r,$w,$x,10);
$timeout=10//秒
对于($i=0;$i<$timeout;$i++){
$in=@fopen($pipePath,'rn');
如果($)中断;
睡眠(1);
}
如果(!$in){
抛出新的RuntimeException(“其他进程未在分配的时间内完成”);
}
$result=fread(8192美元);
fclose(美元);
这使用未记录的
'n'
标志来
fopen
,如上的一条注释所示。如果阻塞,则会导致
fopen
调用立即失败

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

  • 它通过每秒检查一次管道来完成不必要的工作
  • 如果另一个进程中的计算需要1.01秒才能完成,则需要等待整整2秒才能得到结果。对于我想做的一些事情,这已经浪费了足够多的时间,值得尝试解决这个问题
  • 当在URL上调用
    fopen
    时,我可以添加一个上下文参数来指定超时值。但是,这似乎对此不起作用,设置默认套接字超时也不起作用

    有没有更好的方法来处理管道?如果不是,我可能会考虑切换到UNIX套接字,但是在其他进程中,这些不太容易支持,所以我宁愿不这样做。
    (仅供参考,我只关心Linux;不需要在Windows或任何其他系统上运行的东西,以防出现这种情况。)

    我找到了一种方法

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

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

    大概是这样的:

    $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);
    
    $f=fopen("my.fifo","rn");
    $r=array($f);
    $w=array();
    $x=array();
    stream_select($r,$w,$x,10);
    

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

    不确定我为什么没有想到使用select。我认为问题的一部分在于我的问题最初声称
    fopen
    会挂起,但实际上挂起的是
    fread