繁体   English   中英

PHP 不会打开 fifo 进行写入

[英]PHP won't open fifo for writing

我正在围绕一个从命名文件获取输入的复杂二进制文件编写一个小包装器(在 PHP 7.0.33 中)。 由于这将处理机密,我不想将数据提交到文件系统,因此使用 FIFO 而不是传统文件。 二进制文件将愉快地从 FIFO 中读取其数据(使用 2 个 shell 会话进行测试 - 在其中一个我创建了 fifo 并启动了二进制文件,在第二个中我将一个文件放入了 fifo)。

但是在 PHP 中,无论我指定 w、a 还是 c,对 fopen() 的调用都会阻塞

  if (posix_mkfifo("myfifo", 0600)) {
     $writer=fopen("myfifo", 'w'); // this blocks
     `binary myfifo`;
     fputs($writer, $mydata);
  }

虽然如果没有任何内容读取数据,我希望写入会阻塞,但我没想到 fopen() 会阻塞。

它似乎确实可以使用“w +”工作(执行继续,并且二进制文件启动)但是二进制文件失败了

 QIODevice::read (QFile, "filename"): device not open

为了进一步调查,我为二进制文件编写了一个简单的替换。 当我将文件放入 FIFO 时,这同样有效:

$in='';
$fh=fopen($argv[1],'r');
if (is_resource($fh)) {
        print "File opened\n";
        while (!feof($fh)) {
                $in.=fgets($fh);
        }
} else {
        print "failed to open file\n";
}

file_put_contents("output", $in);

但是当我从 PHP 代码写入 FIFO 时......

fopen(import): failed to open stream: No such file or directory in ...

默认情况下,打开 FIFO 将阻塞,直到至少有一个读写器。 这样做的理由是,如果没有进程可以使用 kernel ,则没有地方存储 pipe 数据。 fifo的手册页:

... FIFO 特殊文件在文件系统上没有内容,文件系统条目仅用作参考点,以便进程可以使用文件系统中的名称访问 pipe。

对于由至少一个进程打开的每个 FIFO 特殊文件,kernel 只维护一个 pipe object。 FIFO 必须在两端(读取和写入)都打开,才能传递数据。 通常,打开 FIFO 会阻塞,直到另一端也打开。

不过,您可以绕过此行为。 一种方法就像您所做的那样 - 通过自己打开读写端。 另一种是在打开文件时设置O_NONBLOCK标志(您可以在之后将其设置回阻止)。 AFAIK 你不能用 fopen 做到这一点。 带有dio库的示例:

<?php
echo "Opening\n";
$writer = dio_open("myfifo", O_CREAT | O_WRONLY | O_NONBLOCK) or die("Could not create FIFO\n");
echo "Open. Writing\n";
dio_write($writer, "DATA");
echo "Done\n";

这样做的警告是,如果没有读取器,上述过程将写入数据,然后立即退出,然后数据将永远丢失。

为了任何在 Google 中找到这个问题并寻求比对 semisecure 的答案发表评论更详细的解决方案的人的利益:

if (pcntl_fork()) {
    `binary myfifo`;
} else {
    $fh=fopen('myfifo', 'w');
    fputs($fh, $data);
    fclose($fh);
}

(但您可能还想在编写器上添加一个 SIGALRM 以防“二进制”不执行/刷新管道)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM