1つの接続を使用してサーバーで連続タスクを実行するプロセスを示します

ユーザーがスクリプトをインタラクティブに実行できるようにする必要がありました。 実行要求を受信するバックグラウンドタスクを実行するマルチスレッドPHPボットを実装しました。 彼は自分の活動の結果をデータベースに書き込みます。 次に、実行プロセスについてユーザーに何らかの方法で通知する必要がありました。



通常、この場合、たとえば、彼らは長い要求を行い、その終わりに現在の状態についての応答をサーバーから受信し、その後再び繰り返すか、数秒ごとに状態を確認します。 しかし、1つの接続を使用して、これをより活発に実装したかったのです。



結果のメソッドを使用して、サーバーからの応答を継続的に受信し、中断することなく並行して処理できます。 つまり、それを使用してプロセスの準備状態を取得できるだけでなく、たとえば、巨大なデータを受信プロセスで完全にダウンロードされるのを待たずに処理することもできます。



どのように行動しますか?



この方法は、PHPスクリプトがクライアントにデータを所定の部分で送信するように強制することです。 そして、クライアント側でこれらのサービングを受け取ることで。



残念ながら、多くのブラウザーはAJAXでデータ転送状態を適切に処理する方法を知らないため、数秒で条件付きでデータを同期します。 サーバーからのデータを2秒ごとにリセットし、2秒ごとにクライアント側の新しいデータの到着を確認します。 この場合、多くの場合、矛盾が発生したり、一部のデータが必要以上に新しくなったり、新しいデータがまだありません。 最初のケースのみを考慮します。なぜなら、 pingは、データが過剰であることを保証するのに十分高いと想定されています。



サーバーにデータを強制的に送信します



これを行うには、すべての圧縮方法を禁止し、ブラウザにストリームを送信していることを伝え、ユーザーにすべての出力データを強制的にリセットする必要があります。



また、最も重要な点の1つは、開いているセッションの記録を閉じることです。 実際には、PHPは2つの並列スレッドで同じセッションを開くことができないため、プロセスが動作して並列リクエストを行うと、キューでハングします。 その結果、すべてのAJAX機能が麻痺します。



header('Content-Encoding: none;'); //  header('Content-type: application/octet-stream'); //   ini_set('output_buffering', 'off'); //     php ini_set('zlib.output_compression', false); //         ini_set('implicit_flush', true); ob_implicit_flush(true); //    ,          (!) session_write_close(); for ($i = 0;$i < 20; $i++) { echo '|'.$i.str_repeat(' ', 4096).PHP_EOL; flush(); sleep(2); }
      
      





上記では、セパレータを使用して、最新のデータのみを表示し、送信されたデータを論理部分に分割します。



注-パケットを強制的にユーザーに送信するために、余分な4096バイトを打ち込みます。 それ以外の場合、Webサーバーは、送信に必要なパケットに収集されるまでデータをキャッシュします。 おそらくそれなしで送信する方法があるでしょう、私はコメントで解決策を聞く準備ができています。



上記のスクリプトは、2秒ごとに0〜19の数値を送信し、ブラウザは最新のデータのみを表示します。



クライアント部



 var xhr; var timerlive; function live(cont){ try{ xhr.abort(); }catch(e) { } var temp; clearTimeout(timerlive); var prevtext = ''; xhr = new XMLHttpRequest(); xhr.open('POST', 'ajax.php', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send("type=live"); timerlive = setInterval(function() { if (xhr.readyState == 4) { clearTimeout(timerlive); } temp=xhr.responseText.substring(prevtext.length); $('#'+cont).html(temp.substr(temp.lastIndexOf("|")+1)); prevtext = xhr.responseText; }, 2000); } function breaklive(){ try{ xhr.abort(); }catch(e) { } clearTimeout(timerlive); }
      
      







live()関数の呼び出しは、最初に以前のライブチャネルを中断してから、サーバーへの新しい接続を開始します。 新しいデータの開始点を知るために、古いデータを記録します。 セパレータも使用する| 受信した最新のデータのみを終了します。 一般に、単に最新のデータのみを分離できますが、たとえばオンラインログが生成された場合は、すべての新しいデータを処理できます。



以下に接続を中断するための機能があります。別のページに切り替えたときに接続が閉じられるように、AJAXスクリプトに埋め込むことができます。



All Articles