1

サーバー側とクライアント側で andMySQLを使用してデータベース アプリケーションを作成しました。データベースに変更が加えられるたびに、php ソケットを使用してすべてのクライアントを自動的に更新します。PHPFlex

システム全体はスムーズに動作しますが、時々ソケットが応答を停止しているように見えます。奇妙なことは、接続がまだ良好であることです。クライアントが実行する変更はすべて実装されますが、ソケットはメッセージをブロードキャストしません。ソケット ファイルはエラーをスローしていません (ただし、ソケットから error_log を実行すると、これらのメッセージが表示されます)。ソケットのメモリ使用量はサーバー上で変化せず、切断シグナルは送信されません。それでも見知らぬ人ですが、約30分ほどすると、最終的にソケットが再び機能し始めます。ソケットを再起動すると、問題も解決します。

私は、ソケットが応答しなくなった場合にクライアントがソケットを再起動できるようにするハックなソリューションに取り組んでいますが、それは満足のいくものではなく、間違いを犯す可能性があります。私が本当に望んでいるのは、なぜこれが起こっているのかを学ぶことです. 一定数の接続の後、ソケットはどういうわけか「飽和」しますか? ソケットサーバーをクリーンアップするために何かをする必要がありますか? 3 つの異なる物理サーバー (1 つはローカル、2 つはオンライン) を試しましたが、同じことが起こりました。

私が間違っている基本的な何かがあるように感じます。ソケットサーバーに使用しているコードは次のとおりです (これは、kirupa.com で Raymond Fain によって書かれたソケットのわずかに変更されたバージョンであるため、最初のコメントを上部に残しました):

#!/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', 'Off');

set_time_limit(0);

ob_implicit_flush();

error_log('testing');

$address = 'xxx.xxx.xx.xx';
$port = xxxxx;

function send_Message($allclient, $socket, $buf)
{
    $buf = str_replace("\0","",$buf);
    //echo "<mbFeed>$buf</mbFeed>\n\0";
    foreach($allclient as $client)
    {
        socket_write($client, "<mbFeed>$buf</mbFeed>\n\0");
    }
}


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


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);
    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
            {
                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
            {
                $allclients = $read_sockets;
                array_shift($allclients);
                //any messages starting with ::: are not to be broadcast, and may be used for other things. This message
                //usually comes from the client.
                if (substr($buffer, 0, 3) == ":::") handleSpecial(substr($buffer, 3));
                else
                {
                    //otherwise the message comes from a php file that will be closed, so the socket needs to be closed.
                    unset($read_sockets[$key]);
                    unset($changed_sockets[$key]);
                    socket_close($socket);
                    send_Message($allclients, $socket, $buffer);
                }
            }
        }
    }
}

function handleSpecial($message)
{
    error_log($message);
}
?>
4

1 に答える 1

0

使用中のソケットがブロックしているように見えるため、socket_recv()要求された量のデータが読み取られるまで、への呼び出しが返されない場合があります。これにより、受け入れているソケットを含む他の読み取りソケットは処理されません。

これを回避するsocket_set_nonblock()には、ソケットのブロックを解除します。socket_recv()ノンブロッキング ソケットで を呼び出すと、要求されたよりも少ないバイトを読み取って返される可能性があるため、読み取られたデータの量はソケットごとに追跡されることに注意してください。

于 2012-11-16T18:18:42.683 に答える