我正在尝试使用命名管道在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_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);
这会将未记录的'n'
标记用于fopen
,如this question中的一条评论所示。如果fopen
调用阻塞,它会导致fopen
调用立即失败。
但是,我不喜欢这个解决方案有两个原因:
在URL上调用{{1}}时,我可以添加指定超时值的上下文参数。但是,这似乎不适用于此,也没有设置默认套接字超时。
使用管道有更好的方法吗?如果没有,我可能会考虑切换到Unix套接字,但在其他进程中这些并不那么容易支持,所以我宁愿不这样做。
(仅供参考,我只关心Linux;如果这很重要,不需要在Windows或其他任何东西上运行。)
答案 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的另一端。