0

kirupa の Raymond Fain によるチュートリアルで提供されたものに基づいて、php サーバーを実行しています。

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

ある程度まではうまく機能します。問題は、特定のメッセージを受信すると、そのメッセージに対して何らかの処理を行い、接続されているすべてのクライアントに送信することです。ここでの問題は、クライアントの数が約 12 の大気の高さに達すると、すべてのクライアントにメッセージを送信するループにしばらく時間がかかり (4 秒など)、その 4 秒間に送信された後続のメッセージがキューに入れられることです。そして最終的にタイムアウトになります。

これは、すべてのクライアントにメッセージを送信するループです。

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

マイクロタイムを比較することで、所要時間をエコーし​​ていることがわかるでしょう。問題は、プロセス全体に 0.003 秒程度のわずかな時間がかかることをエコーが主張していることです。これは私が予想していたものですが、ターミナルでこのスクリプトを実行すると、小さな回転アイコンが表示されます4 秒間、すべてが応答しなくなります。

私の質問は次のとおりです。スクリプトがその間に何をしているか知っている人はいますか? それを止めるために私にできることはありますか?接続されているすべてのソケットにメッセージを送信するより効率的な方法はありますか?

必要に応じて、ソケットファイル全体のコードを次に示しますが、これが誰かになじみのあるものであることを願っています...

#!/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\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));
                }
            }
        }
    }
}
?>
4

1 に答える 1

1

ステロイドのソケットのようなZeroMQを見ることをお勧めします

百語で言えば ØMQ

ØMQ (ZeroMQ、0MQ、zmq とも呼ばれます) は、組み込み可能なネットワーク ライブラリのように見えますが、同時実行フレームワークのように機能します。インプロセス、インタープロセス、TCP、マルチキャストなどのさまざまなトランスポートでアトミック メッセージを運ぶソケットを提供します。ファンアウト、pub-sub、タスク分散、リクエスト/リプライなどのパターンを使用して、ソケットを N 対 N で接続できます。クラスター化された製品のファブリックとして十分に高速です。その非同期 I/O モデルは、非同期メッセージ処理タスクとして構築されたスケーラブルなマルチコア アプリケーションを提供します。多くの言語 API があり、ほとんどのオペレーティング システムで動作します。ØMQ は iMatix からのもので、LGPLv3 オープン ソースです。

同じチャットサーバーを使用するZMQ::SOCKET_PUBZMQ::SOCKET_PULL、次のように簡単になります

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

10,000これにより、現在のサーバー実装とは対照的に、単純なシステムで 1 分あたりのプッシュ リクエストを簡単に処理できます。

ZmqSocketを使用すると、JavaScript コードから zmq ソケットと通信できます文字列メッセージを接続、送受信できます。JavaScript は未加工の TCP 接続をサポートしていないため、Flash をブリッジとして使用します。

シンプルな JavaScript ブリッジの例zmqsocket-as も参照できます。これにより、ActionScript コードから zmq-sockets と通信できます。

于 2012-11-28T17:56:56.010 に答える