4

我想编写一个 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 命令并让它们执行。只要我的网络服务器在 LAMP 环境中工作,这在任何情况下都应该有效。缺点是它不能在 WAMP 环境中工作。

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

PS:我需要阻塞管道让读者等到一个事件被发送。我知道管道可以在非阻塞模式下使用

stream_set_blocking($pipe,false);

大约是这样,但整个想法是在不使用管道进行轮询的情况下做到这一点,一旦事件被触发,它就会唤醒阅读器。

4

3 回答 3

4

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

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 调用writePipe_test(),那么它会等到进程 2 调用 readPipe_test()从管道中读取数据。

如果进程 1 调用readPipe_test(),那么它会一直等到进程 2 调用 writePipe_test()将某些内容写入管道。

诀窍是 'w' 和 'r' 而不是 'r+'。

于 2013-01-18T16:39:56.817 回答
1

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

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

如果您按以下方式更改它,它将起作用:

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

编辑:或将 $pipeA 设置为具有全局范围,就此而言..

于 2013-01-18T14:11:22.580 回答
0

我不确定我是否理解你的第二个帖子..

但是要评论最后一个,如果我没有误解,TCP可能会更复杂,因为您必须先建立连接才能读取或写入,因此您有不同的开销

至于在函数结束时关闭的管道句柄,我假设您将面临与套接字相同的问题;但管道文件仍然存在!

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

于 2013-01-19T02:04:01.240 回答