2

私はこのサイトを初めて使用するので、質問に関して必要な情報をすべて提供できることを願っています。

ロングポーリングを使用して「新しいメッセージが到着した通知」を作成しようとしています。window.onLoad現在、サイトの各ページのイベントごとにポーリング リクエストを開始しています。

サーバー側では、無限ループがあります。

while(1){
 if(NewMessageArrived($current_user))break;
 sleep(10);
}
echo $newMessageCount;

クライアント側には、次の (簡略化された) ajax 関数があります。

poll_new_messages(){
 xmlhttp=GetXmlHttpObject();
 //...
 xmlhttp.onreadystatechange=got_new_message_count;
 //...
 xmlhttp.send();
}

got_new_message_count(){
 if (xmlhttp.readyState==4){
  updateMessageCount(xmlhttp.responseText);
  //...
  poll_new_messages();
 }
}

問題は、ページが読み込まれるたびに、上記のループが再び開始されることです。その結果、ユーザーごとに複数の無限ループが発生し、最終的にサーバーがハングします。

*このNewMessageArived()関数は、MySQL DB にクエリを実行して新しい未読メッセージを探します。

*値start_session()を取得するために実行するphpスクリプトの最初に。$current_user

time()現在、このサイトの唯一のユーザーであるため、このループ内のファイルに書き込むことで、この動作を簡単にデバッグできます。私が見ているのは、ファイルが 10 秒に 1 回以上書き込まれているということですが、ページからページに移動したときにのみ開始されます。

追加情報が役立つ場合はお知らせください。

ありがとうございました。

4

3 に答える 3

1

長いポーリング要求が30秒後にタイムアウトするのはよくあることのようです。したがって、whileループでは、30秒後に「CLOSE」をエコーできます。

while(!$new_message && $timer < 30){
    $new_message = NewMessageArrived($current_user);
    if(!$new_message) {
        sleep(10);
        $timer += 10;
    }
}
if($newMessageCount) {
    echo $newMessageCount;
} else {
    echo 'CLOSE';
}

Javascriptでは、CLOSEをリッスンできます。

function poll_new_messages(){
    xmlhttp=GetXmlHttpObject();
    //...
    xmlhttp.onreadystatechange=got_new_message_count;
    //...
    xmlhttp.send();
}

function got_new_message_count(){
    if (xmlhttp.readyState==4){
        if(xmlhttp.responseText != 'CLOSE') {
            updateMessageCount(xmlhttp.responseText);
        }
        //...
        poll_new_messages();
    }
}

これで、PHPは、何があっても30秒以内に応答を返します。ページにとどまるを使用していて、CLOSEを受け取った場合は、ページのカウントを更新せずに、再確認してください。

ユーザーが新しいページに移動すると、PHPインスタンスは30秒以内にループを停止し、応答を返します。ただし、新しいページにいるため、その接続を気にしたXHRは存在しないため、別のループは開始されません。

于 2009-11-23T21:02:21.277 に答える
1

私は自分の問題の解決策を見つけたと思います。これが COMET で使用されている手法であり、このソリューションがどれほどスケーラブルかを誰かが教えてくれれば幸いです。

次のようなユーザーベースのセマフォを使用しました。

$sem_id = sem_get($current_user);
sem_acquire($sem_id);
while(1){
 if(NewMessageArrived($current_user))break;
 sleep(10);
}
sem_release($sem_id);
echo $newMessageCount;
于 2009-11-24T19:59:57.570 に答える
0

connection_aborted()定期的にチェックしてみてください。connection_aborted()いくつかの出力を書き込んでを実行するまで、接続が実際に中止されたという事実に気付かない可能性があることに注意してくださいflush()

実際、phpが接続が閉じたことに気づき、スクリプトを自動的に強制終了するには、定期的に出力を生成するだけで十分な場合があります。

于 2009-11-23T21:01:32.947 に答える