php socket fast way to send message to multiple clients?

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";
    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 ray@obi-graphics.com
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";
    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("","",$buffer));
                }
            }
        }
    }
}
?>

Leave a Reply

*

Hire Me
Follow Me!
Search
Most Popular Articles & Pages
Because your vote is Important
Sorry, there are no polls available at the moment.
Categories