0

I'm running a php server based on the one provided by a tutorial by Raymond Fain on kirupa:

http://www.kirupa.com/developer/flash8/php5sockets_flash8_3.htm

It works great, up to a point. The thing is that when it receives certain messages, it then does some stuff to that message then sends it out to all connected clients. The problem here is that once the number of clients reaches the atmospheric heights of around 12, the loop that sends the message to all clients can take a while (like 4 seconds), and any subsequent messages sent during that 4 second period get queued up and eventually we get timeouts.

This is the loop that sends a message to all clients:

function send_Message($allclient, $socket, $buf)
{
    $now = microtime(true);
    echo 'sending message to '.count($allclient).' clients ';

    $msg = "<mbFeed>$buf</mbFeed>\n\0";
    foreach($allclient as $client)
    {
        socket_write($client, $msg, strlen($msg));
    }

    $end = microtime(true);
    echo 'time was '.($end - $now);
}

You'll notice I've been echoing the time it takes by comparing microtimes. The thing is that the echo claims that the whole process takes a tiny amount of time, like 0.003 seconds, which is what I would have expected, but when I have this script running in the terminal, I see the little spinning icon going for the four seconds, during which everything gets unresponsive.

My questions are as follows: does anyone know what the script is doing during that time? Is there anything I can do it to stop it doing that? Is there a more efficient way to send a message to all connected sockets?

Here's the code for the whole socket file, if you need it, but I'm hoping this is something that might be familiar to somebody...

#!/usr/bin/php -q
<?php
/*
Raymond Fain
Used for PHP5 Sockets with Flash 8 Tutorial for Kirupa.com
For any questions or concerns, email me at [email protected]
or simply visit the site, www.php.net, to see if you can find an answer.
*/

//ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(E_ALL);
//ini_set('error_log', 'socket_errors.log');
ini_set('log_errors', 'On');
ini_set('display_errors', '1');

error_log('testing');

stream_set_timeout(1,0);

set_time_limit(0);

ob_implicit_flush();

$address = 'xxx.xxx.x.xxx';
$port = xxxx;

function send_Message($allclient, $socket, $buf)
{
    $now = microtime(true);
    echo 'sending message to '.count($allclient).' clients ';

    $msg = "<mbFeed>$buf</mbFeed>\n\0";
    foreach($allclient as $client)
    {
        socket_write($client, $msg, strlen($msg));
    }

    $end = microtime(true);
    echo 'time was '.($end - $now);
}


echo "connecting...
";
//---- Start Socket creation for PHP 5 Socket Server -------------------------------------

if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0)
{
    echo "socket_create() failed, reason: " . socket_strerror($master) . "\n";
}

socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);
socket_set_nonblock($master);


if (($ret = socket_bind($master, $address, $port)) < 0)
{
    echo "socket_bind() failed, reason: " . socket_strerror($ret) . "\n";
}

echo 'socket bind successfull.
';


if (($ret = socket_listen($master, 5)) < 0)
{
    echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";
}

$read_sockets = array($master);

echo "connected.";

//---- Create Persistent Loop to continuously handle incoming socket messages ---------------------
while (true)
{ 
    $changed_sockets = $read_sockets;
    $num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);

    echo 'changed sockets length: '.(count($changed_sockets));

    foreach($changed_sockets as $key => $socket)
    {
        if ($socket == $master)
        {
            if (($client = socket_accept($master)) < 0)
            {
                echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
                continue;
            } 
            else
            {
                socket_set_nonblock($client);
                array_push($read_sockets, $client);
            }
        }
        else
        {
            $bytes = socket_recv($socket, $buffer, 8192, 0);

            if ($bytes == 0)
            {
                unset($read_sockets[$key]);
                unset($changed_sockets[$key]);
                socket_close($socket);
            }
            else
            {
                if (substr($buffer, 0, 3) == "<->")
                {
                    unset($read_sockets[$key]);
                    unset($changed_sockets[$key]);
                    socket_close($socket);

                    $buffer = substr($buffer, 3);
                }

                $allclients = $read_sockets;
                array_shift($allclients);
                if (substr($buffer, 0, 3) == ":::") handleSpecial(substr($buffer, 3));
                else
                {
                    echo 'allclients length: '.(count($allclients));
                    send_Message($allclients, $socket, str_replace("\0","",$buffer));
                }
            }
        }
    }
}
?>

1 Answer 1

1

I would like to recommend you to look at ZeroMQ its like sockets on steroids

ØMQ in a Hundred Words

ØMQ (also seen as ZeroMQ, 0MQ, zmq) looks like an embeddable networking library but acts like a concurrency framework. It gives you sockets that carry atomic messages across various transports like in-process, inter-process, TCP, and multicast. You can connect sockets N-to-N with patterns like fanout, pub-sub, task distribution, and request-reply. It's fast enough to be the fabric for clustered products. Its asynchronous I/O model gives you scalable multicore applications, built as asynchronous message-processing tasks. It has a score of language APIs and runs on most operating systems. ØMQ is from iMatix and is LGPLv3 open source.

using ZMQ::SOCKET_PUB and ZMQ::SOCKET_PULL the same chat server can be as simple as

$ctx = new ZMQContext();
$pub = $ctx->getSocket(ZMQ::SOCKET_PUB);
$pub->bind('tcp://*:5566');
$pull = $ctx->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://*:5567');


echo "Chat Server Start ", PHP_EOL;

while(true) {
    $message = $pull->recv();
    echo "Got ", $message, PHP_EOL;
    $pub->send($message);
}

This can easily handle10,000 push request per min on a simple system as oppose to your current server implementation.

With ZmqSocket you can talk to zmq sockets from your JavaScript code. You can connect, send and receive string messages. As JavaScript does not support raw TCP connections, it uses Flash as a bridge

Simple JavaScript Bridge Example you can also look at zmqsocket-as which allows you to talk to zmq-sockets from ActionScript code.

Sign up to request clarification or add additional context in comments.

3 Comments

Hi there! Thanks for responding. I've taken a while to respond simply because I took you at your word and have tried to use ZeroMQ for my project. It seems to be working, but I still have an issue: While using the pull - pub model you suggest, I find that if I send multiple messages at the same time, only one of them gets sent to my application. I can solve this by adding a usleep() command within the while loop, but that seems unsatisfactory to me. Any ideas why it doesn't work?
More a more advance chat system you are to be using ZMQ::SOCKOPT_SUBSCRIBE and ZMQPoll(); ... to can do a little more research and those ... Just curios you are using my advice and you did not even accept .. anyway best of luck on your research
Hehe! Wanted to make sure it was right for me! In any case, whether or not everything works out, I'm certainly enjoying learning about it, and thanks a lot for your help. Sorry for taking a while. My only issue is that I feel a little bit lost at sea with zeromq – searches don't always come up with stuff a low level guy like myself can follow. That said, what you've just said about SMQPoll and the like rings a few bells from my stumbling in the dark, and I'll renew my efforts. Thanks again!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.