3

アプリケーションのいくつかのページで、ゲーム サーバーにクエリを実行するソケットがあります。ページ間をすばやく移動すると、ソケットが適切に閉じられず、エラーが発生するという問題があります。

socket_recv() [function.socket-recv]: unable to read from socket [104]: Connection reset by peer

各ページが完全に読み込まれてから閉じるまで、約 4 ~ 5 秒待つ必要があります。

ソケットのコードは次のとおりです。

function QueryMinecraft( $IP, $Port, $Timeout =1 )
{
    $Socket = Socket_Create( AF_INET, SOCK_STREAM, SOL_TCP );

    Socket_Set_Option( $Socket, SOL_SOCKET, SO_SNDTIMEO, array( 'sec' => (int)$Timeout, 'usec' => 0 ) );

    if( $Socket === FALSE || @Socket_Connect( $Socket, $IP, (int)$Port ) === FALSE )
    {
        Socket_Close( $Socket );
        return FALSE;
    } else {
        Socket_Close( $Socket );
        return TRUE;
    }      
    Socket_Close( $Socket );                  
}   

そして、これが別のページのソケットのコードです。

function QueryMinecraft( $IP, $Port, $Timeout = 3 )
{
    $Socket = Socket_Create( AF_INET, SOCK_STREAM, SOL_TCP );

    Socket_Set_Option( $Socket, SOL_SOCKET, SO_SNDTIMEO, array( 'sec' => (int)$Timeout, 'usec' => 0 ) );

    if( $Socket === FALSE || @Socket_Connect( $Socket, $IP, (int)$Port ) === FALSE )
    {
        return FALSE;
    }

    Socket_Send( $Socket, "\xFE", 1, 0 );
    $Len = Socket_Recv( $Socket, $Data,256, 0 );


    if( $Len < 4 || $Data[ 0 ] != "\xFF" )
    {
        return FALSE;
    }

    $Data = SubStr( $Data, 3 );
    $Data = iconv( 'UTF-16BE', 'UTF-8', $Data );
    $Data = Explode( "\xA7", $Data );

    return Array(
        'HostName'   => SubStr( $Data[ 0 ], 0, -1 ),
        'Players'    => isset( $Data[ 1 ] ) ? IntVal( $Data[ 1 ] ) : 0,
        'MaxPlayers' => isset( $Data[ 2 ] ) ? IntVal( $Data[ 2 ] ) : 0
    );
}

ありがとう!

4

1 に答える 1

3

うわー、私がよく知っている特定の知識!マインクラフトのタグがあるはずです。

これは実際には Minecraft サーバーの制限であり、php コードの問題ではないと思います。minecraft クライアントを使用していて、マルチプレイヤー ページに何度もすばやくアクセスすると、同じ問題が発生することに気付くかもしれません (プレイヤー数をクエリするためのサーバーへの接続と MOTD は拒否されます)。訪問の合間に 5 ~ 6 秒待つと、自然に解決します。

したがって、解決策は、サーバーからの応答を 10 秒または 30 秒ほどキャッシュして、サーバーが応答を拒否しないようにすることです。

使用できるローカル SQL データベースがあるかどうかはわかりませんが、サーバーの ip を含むテーブルを自分で設定できるはずです (一意であることが保証されていないホスト名ではありません。ip はどちらでもありませんしかし、より良い賭け)、MOTD、現在および最大のプレーヤー、および最後にチェックされたタイムスタンプ。データベースクエリを実行し、タイムスタンプをチェックして、キャッシュされた値が期限切れになっていないことを確認し、期限切れになっている場合は、サーバーに直接クエリを実行して、結果をデータベースに保存するだけです。

于 2012-09-07T21:53:01.493 に答える