如何在PHP中在不同的函数甚至不同的进程之间使用命名管道,而不需要fork


How to use named pipes in PHP between different functions or even different processes without fork?

我想写一个Ajax web应用程序,具体来说是一个游戏。两个web客户端必须通过PHP服务器相互通信。我解决这个问题的方法是在客户机和服务器以及服务器和客户机之间使用Ajax。每个客户机使用Ajax创建一个单独的服务器进程。我希望这两个服务器进程通过MySQL和命名管道进行通信。我需要命名管道来获得整个应用程序的即时响应。

我不能使用一个服务器进程,它首先创建一个管道,然后分叉成两个使用该管道的进程。Web应用程序在Web浏览器发送请求时创建服务器进程。因此,我需要命名管道,其中每个进程只知道命名管道的文件名。他们不能交换文件句柄(至少我不知道如何)。

我的问题是PHP中的命名管道确实可以工作,只要它们是在同一函数中使用:

public function writeAndReadPipe_test(){
    $pipeA = fopen("testpipe",'r+');
    fwrite($pipeA, 'ABCD');
    $pipeB = fopen("testpipe",'r+');
    $content = fread($pipeB, 4);
    echo "[" . $content . "]<br>'n";
}
public function testingPipes_same_function(){
    posix_mkfifo("testpipe", 0777);
    $this->writeAndReadPipe_test();
}

但是,当我使用不同的功能时,那么 fread($pipeB, 4) 命令会阻塞整个应用程序:

public function writePipe_test(){
    $pipeA = fopen("testpipe",'r+');
    fwrite($pipeA, 'ABCD');
}
public function readPipe_test(){
    $pipeB = fopen("testpipe",'r+');
    $content = fread($pipeB, 4);
    echo "[" . $content . "]<br>'n";
}
public function testingPipes_different_functions(){
    posix_mkfifo("testpipe", 0777);
    $this->writePipe_test();
    $this->readPipe_test();
}

有人知道为什么吗?在第一步中,我怎么做才能使它在不同的函数之间起作用呢?在第二步中,它甚至可以在不同的进程之间工作!我还发现,当编写器在阅读器读取之前关闭管道时也会出现问题它。我猜想函数会在它结束时自动关闭它,但这只是一个猜测。

如果PHP的方式不起作用,我计划让PHP打开命令行,生成BASH命令并执行它们。这应该在任何情况下工作,只要我的web服务器在LAMP环境中工作。缺点是它不能在WAMP环境中工作。

那么,有人对此有什么想法吗?

p。史:我需要阻塞管道,让读者等待,直到事件发送。我知道管道可以使用

在非阻塞模式下工作
stream_set_blocking($pipe,false);

之类的,但整个想法是在不轮询的情况下完成它,只是使用管道,这会唤醒在事件触发后立即启动Reader

只是一个简短的声明,我实际上找到了一个很好的解决方案使用命名管道:

public function createPipe_test(){
    posix_mkfifo("testpipe", 0777);
}
public function writePipe_test($value){
    $pipeA = fopen("testpipe",'w');
    $valueString = number_format($value);
    $valueLen = number_format(strlen($valueString));
    fwrite($pipeA, $valueLen);
    fwrite($pipeA, $valueString);
}
public function readPipe_test(){
    $pipeB = fopen("testpipe",'r');
    $valueLen = fread($pipeB, 1);
    return fread($pipeB, $valueLen);
}

我有两个进程。

如果进程1调用 writeppe_test (),则等待进程2调用readPipe_test()从管道中读取数据。

如果进程1调用readPipe_test(),则等待进程2调用 writeppe_test ()向管道中写入内容。

技巧是用'w'和'r'代替'r+'。

当您像这样在单独的函数中使用管道时,写管道A似乎再次被关闭/丢弃($pipeA的局部作用域)。假设必须打开管道进行读取和/或写入,以便保留任何信息,这确实是有意义的。虽然我不知道内在的魔力。

您还可以观察到,当您从另一个进程(如echo magic>> testpipe)提供管道时,阻塞读调用会成功。因此,您已经完成了第2步,但您需要一些管道句柄管理。

如果你像下面这样修改它就可以了:

    private $pipeA;
    public function writePipe_test(){
        $this->pipeA = fopen("testpipe",'r+');
        fwrite($this->pipeA, 'ABCD');
    }

编辑:或者设置$pipeA具有全局作用域。

我不确定我是否理解你的第二篇文章。

但是要评论最后一个,如果我没有误解的话,TCP可能更复杂,因为你必须在读取或写入之前建立连接,所以你有不同的开销

至于在函数端关闭的管道句柄,我认为您将面临与套接字相同的问题;但是管道文件仍然存在!

持久存储(文件,数据库)将使客户端在时间上独立,如果你想使用阻塞调用,那么文件实际上可能是一种方法。