How to use named pipes in PHP between different fu

2019-02-19 16:09发布

问题:

I want to write an Ajax web application, a game to be specific. Two web clients have to communicate with each other via the PHP server. My approach to solve this is to use Ajax between client and server and server and client. Each client creates a separate server process using Ajax. I want that these two server processes communicate via MySQL and via named pipes. I need the named pipes to get immediate response for the whole application.

I cannot use one server process, which first creates a pipe and then forks into two processes, which use the pipe. Web applications create server processes when the web-browser sends a request. So, I need named pipes, where each process doesn't know more than the file name of the named pipe. They cannot exchange file handles (at least I don't know how).

My problem is that named pipes in the PHP way indeed work as long as they are used within the same function:

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();
}

But, when I use different functions, then the fread($pipeB, 4) command blocks the whole application:

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();
}

Does anybody know why? And what can I do to make it work between different functions in the first step? In the second step, it should work even between different processes! I found out that I also get a problem when the writer closes the pipe before the reader reads from it. I suppose that the function closes it automatically when it ends, but this is only a guess.

If the PHP way does not work, I plan to let PHP open a command line, generate BASH commands and let execute them. This should work in any case as long as my web-server works in a LAMP environment. Disadvantage is that it will not work in WAMP environments.

So, has anybody some ideas to this?

P.S: I need blocking pipes to let the reader wait until an event is sent. I know that the pipes can work in a non-blocking mode using

stream_set_blocking($pipe,false);

or so, but the whole idea is to do it without polling just using a pipe, which wakes the reader up as soon as an event is fired.

回答1:

When you use the pipes in separate functions like this, the write pipe A would seem to be closed/discarded again (local scope of $pipeA). The assumption would be that the pipe must be opened for reading and/or writing in order to retain any info, which makes sense really. Though I don't know the inner magic.

You can also observe that your blocking read-call succeeds when you feed the pipe from another process (like echo magic >> testpipe). So you'd already have step 2 done, but you need some pipehandle management.

If you change it as follows it'd work:

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

Edit: or setting $pipeA to have global scope, for that matter..



回答2:

Just a short statement, that I actually found a nice solution using named pipes:

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);
}

I have two processes.

If process 1 calls writePipe_test(), then it waits until process 2 calls readPipe_test() to read the data out of the pipe.

If process 1 calls readPipe_test(), then it waits until process 2 calls writePipe_test() to write something into the pipe.

The trick is 'w' and 'r' instead of 'r+'.



回答3:

Im not sure wether I understand your 2nd last post..

But to comment on the last one, if I don't misunderstand, TCP might be even more complex because you will have to establish a connection before you can either read or write, so youve got different overhead

As for the pipehandle closing at the function end, I assume you'll face the same problem with the sockets; but the pipefile remains!

Persistent storage (files,db) would make the clients independent timingwise, if you want to use blocking calls then files might actually be a way to go..