17

I'm using popen with fgets to read the output of tcpdump asynchronously.

The below code should be run in the command line, not with apache and viewing it in your browser.

$handle = popen('tcpdump -nnX', 'r');

while (true) {
    $output = fgets($handle);
    print $output . "\n";
}

The problem arises when I try to output this information via websockets.

Websockets also use an infinite loop (for managing its sockets, ticks, and messages).

It looks something like:

while (true) {
    @socket_select($read,$write,$except,1);
    foreach ($read as $socket) {
        if ($socket == $this->master) {
            $client = socket_accept($socket);
...

I send data through the websocket with $websocket->sendToAll($message);.

  • I can't put the while loops one after the other because it will only run whichever loop I put first, while (true) { A() }; while (true) { B() }; B() will never be called

  • I can't merge the while loops, because the websockets slows down the reading of popen, and vise versa. while (true) { A(); B(); } if B is taking a long time to finish, A will be slow to run.

What can I do in this situation? I'm open to the idea of threads, communication between forked scripts, or anything else.

Dave Chen
  • 10,887
  • 8
  • 39
  • 67
  • Not cool, crashed my browser and made explorer go crazy, put a warning >. – Craig van Tonder Sep 12 '15 at 11:02
  • @IndigoIdentity Added. My question solely focuses on cli, no browser involved here. (Except for viewing with websockets, but that code is omitted here) – Dave Chen Sep 12 '15 at 11:05
  • Okay, it was partially my own fault as I was pinging IP's over sockets earlier and outputting into the browser so I already had this mind set ingrained in me. Thinking about it now, asynchronous socket connections in PHP would be awesome. Nice question! – Craig van Tonder Sep 12 '15 at 11:07
  • I think this can be solved by either having async websockets or async shell_exec. [This](http://stackoverflow.com/questions/222414/asynchronous-shell-exec-in-php) ignores output. I might just use node.js because of [this](http://stackoverflow.com/a/23516933/2344142). – Dave Chen Sep 12 '15 at 11:25
  • This was interesting: https://segment.com/blog/how-to-make-async-requests-in-php/ – Craig van Tonder Sep 12 '15 at 11:26

2 Answers2

7

This is the classic scenario for Producer-Consumer problem. It's just that you've got two of them. You can break down the problem to understand it easier.

  • WebSocket Consumer: This code will send data through WebSocket. You can consider this a separate thread in which data is dequeued from Q1 (just a name) and sent.

  • WebSocket Producer: Once some data arrives at at the WebSocket gate, it is enqueued into a buffer. It's just that this is not the same queue as above. Let's name it Q2. This needs to be a separate thread as well, and this thread goes to sleep once it enqueues the data and signals the appropriate consumer.

  • HDD Consumer: This code will do the same as WebSocket Consumer, the only difference is that it will store the data on a hard disk instead of WebSocket. It will have its own thread and works with Q2.

  • HDD Producer: I'm sure you can guess what this does. This code will read data off the hard disk and put it in Q1 queue. Like all the producers it needs to signal its consumers informing them of a new item in queue.

Now getting back to your code, PHP is not suitable for multi-thread programming even though it's completely possible. That's why you can not find that many examples for it. But if you insist, here are what you'll need:

  1. PHP's Thread class

  2. PHP's Mutex class. This class will help you prevent multiple threads to access the same data at the same time.

  3. Something call Signaling which I can not find in PHP! It is used to tell other threads that some data in queue is ready to be consumed, or in other words, it will wake up the consumer thread when it has something to do.

Final word is that in a proper multi thread software you won't be using sleep function to lower system's load / preventing system crash. Multi-thread programming is all about signaling and conversation between threads.

Mehran
  • 15,593
  • 27
  • 122
  • 221
  • POSIX signals in PHP: https://secure.php.net/manual/en/function.pcntl-signal.php -- This defines a signal handler. – Ghedipunk Sep 16 '15 at 10:45
  • @Ghedipunk Thanks, but I think those functions are made for inter-process communication not inter-thread. Since we are talking about multi-threading, the whole script will be within one process, thus suspending a thread using PCNTL functions should suspend all of the threads in the process. I must confess I haven't tried it myself and it's all what I believe. – Mehran Sep 16 '15 at 11:59
  • Good point, I haven't tried it in a multi-threaded environment either. It's something to play with, at least. I have to admit I personally avoid multi-threading in favor of forking. – Ghedipunk Sep 16 '15 at 16:05
  • 1
    I'm sure you know cons & pros of multi-process vs multi-thread programming. But just for the record, in multi-thread, shared memory comes easy because all threads are in the same context. But in multi-process programming, even though you have shared memory but it's not as easy as multi-thread. – Mehran Sep 17 '15 at 06:31
2

How about wscat? The following command line:

$ printf "hello\\nbye\\n^C" | wscat -c ws://echo.websocket.org

sends the two lines below to ws://echo.websocket.org.

hello
bye

Note that ^C in the command line is a Control-C (not a two-letter combination of ^ and C).

Takahiko Kawasaki
  • 18,118
  • 9
  • 62
  • 105