19

私はを使用して理論的な Web チャット アプリケーションを作成しようとしています。ロング ポーリングと http ストリーミングについて読み、記事で紹介されているほとんどの原則を適用することができました。ただし、まだ理解できないことが 2 つあります。

ロングポーリングあり

  • 更新が送信されたことをサーバーはどのように知るのですか? データベースを継続的にクエリする必要がありますか、それともより良い方法がありますか?

HTTP ストリーミングあり

  • Ajax 接続がまだアクティブなときに結果を確認するにはどうすればよいですか? ajax 呼び出しに対するjQuery の機能は認識していますが、接続successのデータを確認するにはどうすればよいですか?

事前に感謝します。

4

2 に答える 2

25

ええ、コメットのようなテクニックは通常、最初は脳を吹き飛ばします。もう 1 つの問題は、PHP で使用できるリソースがそれほど多くないことです。誰もが Node.js、Python、Java などで Comet を実行しているためです。

私はあなたの質問に答えようとします。それが人々にとってこのトピックに光を当てることを願っています.

更新が送信されたことをサーバーはどのように知るのですか? データベースを継続的にクエリする必要がありますか、それともより良い方法がありますか?

答えは次のとおりです。最も一般的なケースでは、メッセージ キュー (MQ) を使用する必要があります。RabbitMQ または Redis ストアに組み込まれている Pub/Sub 機能が適切な選択かもしれませんが、ZeroMQ、Beanstalkd など、市場には競合するソリューションが数多くあります。

したがって、データベースに継続的にクエリを実行する代わりに、MQ イベントをサブスクライブして、サブスクライブしたメッセージを他の誰かが公開し、MQ があなたを目覚めさせてメッセージを送信するまでハングすることができます。チャット アプリは、この機能を理解するための非常に優れたユース ケースです。

また、他の言語で Comet-chat の実装を検索すると、MQ を使用していない単純なものに気付くかもしれません。では、彼らはどのように情報を交換するのでしょうか? 問題は、そのようなソリューションは通常、スタンドアロンのシングルスレッド非同期サーバーとして実装されるため、すべての接続をスレッド ローカル配列 (または類似のもの) に格納し、単一のループで多くの接続を処理し、1 つを選択して必要なときに通知することができます。このような非同期サーバーの実装は、Comet-technique に非常に適した最新のアプローチです。ただし、Comet を mod_php または FastCGI の上に実装する可能性が最も高いです。この場合、この単純なアプローチはオプションではなく、MQ を使用する必要があります。

これは、単一のスレッドで多くの接続を処理するためにスタンドアロンの非同期 Comet サーバーを実装する方法を理解するのに非常に役立ちます。最近のバージョンの PHP は Libevent と Socket Streams をサポートしているため、この種のサーバーを PHP でも実装できます。PHP ドキュメントにもサンプルがあります。

Ajax 接続がまだアクティブなときに結果を確認するにはどうすればよいですか? jQuery の ajax 呼び出しの成功関数については認識していますが、接続中のデータを確認するにはどうすればよいですか?

プレーンな XHR、jQuery Ajax などの通常の Ajax 手法を使用して長時間実行されるポーリングを実行している場合、単一の Ajax リクエストで複数の応答を送信する簡単な方法はありません。あなたが言及したように、応答全体を処理するための「成功」ハンドラーのみがあり、その部分は処理しません。回避策として、リクエストごとに 1 つの応答のみを送信し、それを「成功」ハンドラーで処理します。その後、新しいロング ポール リクエストを開きます。これが HTTP プロトコルの仕組みです。

IFRAMEまた、実際には、非表示の無限に長いページやマルチパート HTTP 応答の使用などの手法を使用して、さまざまな手法を使用してストリーミングのような機能を実装する回避策があることにも言及する必要があります。これらの方法は両方とも特定の欠点です (前者は信頼性が低いと見なされ、無限ロード インジケーターなどの望ましくないブラウザー動作を生成する可能性があり、後者は一貫した単純なクロスブラウザー サポートを漏らしますが、特定のアプリケーションは依然としてそれに依存していることが知られています)。ブラウザーがマルチパート応答を適切に処理できない場合にロング ポーリングにフォールバックするメカニズム)。

単一の要求/接続ごとに複数の応答を信頼できる方法で処理したい場合は、最新のブラウザーでサポートされている WebSocket などのより高度なテクノロジの使用を検討する必要があります。たとえば、モバイルアプリ用に開発する場合)。

メッセージ キューについて詳しく教えてください。

Message Queueは、オブザーバー パターン(「パブリッシュ/サブスクライブ」または単に PubSub とも呼ばれます) のスタンドアロン (または組み込み) 実装を表す用語です。大きなアプリケーションを開発する場合、1 つあると非常に便利です。これにより、システムのさまざまな部分を切り離し、イベント駆動型の非同期設計を実装して、特に異種システムでの作業がずっと楽になります。これには実世界のシステムへの多くのアプリケーションがあります。そのうちの 2 つだけを紹介します。

  • タスク キュー。独自の YouTube を作成していて、バックグラウンドでユーザーのビデオ ファイルを変換する必要があるとしましょう。動画をアップロードするための UI と、動画ファイルを変換するための固定数のワーカー プロセスを備えた Web アプリケーションが必要なのは明らかです (おそらく、ワーカーだけが離れる専用サーバーがいくつか必要になる場合もあります)。また、より良いパフォーマンスを確保するために、ワーカーを C で作成する必要があるでしょう。あとは、メッセージ キュー サーバーをセットアップして、ビデオ変換タスクを収集し、Web アプリケーションからワーカーに配信するだけです。ワーカーが生成されると、MQ に接続し、新しいタスクを待機してアイドル状態になります。誰かがビデオ ファイルをアップロードすると、Web アプリケーションは MQ に接続し、新しいジョブでメッセージを発行します。RabbitMQなどの強力な MQ接続されているワーカーの数にタスクを均等に分散し、完了したタスクを追跡し、何も失われないようにし、フェイルオーバーを提供し、現在保留中のタスクと統計を閲覧するための管理 UI を提供します。
  • 非同期動作。私たちのコメットチャットは良い例です。明らかに、常にデータベースを定期的にポーリングする必要はありません (では、Comet の用途は何でしょうか? -- 定期的な Ajax リクエストを行うことと大きな違いはありません)。新しいチャット メッセージが表示されたときに通知してくれる人が必要です。そして、メッセージ キューはその誰かです。Redisのキー/バリュー ストアを使用しているとしましょう。これは、データ ストア機能の中でPubSub実装を提供する非常に優れたツールです。最も単純なシナリオは次のようになります。
    1. 誰かがチャット ルームに入ると、新しい Ajax ロング ポール リクエストが行われます。
    2. サーバー側のリクエスト ハンドラーは、'newmessage' チャネルをサブスクライブするコマンドを Redis に発行します。
    3. 誰かがチャットにメッセージを入力すると、サーバー側のハンドラーがメッセージを Redis の「newmessage」トピックに発行します。
    4. メッセージが発行されると、Redis は、以前にそのチャネルにサブスクライブしたすべての保留中のハンドラーにすぐに通知します。
    5. ロング ポール リクエストを開いたままにしておく通知の PHP コードは、新しいチャット メッセージでリクエストを返すことができるため、すべてのユーザーに通知されます。その時点でデータベースから新しいメッセージを読み取るか、メッセージ ペイロード内でメッセージを直接送信することができます。

私の図が理解しやすいことを願っていますが、メッセージ キューは非常に広範なトピックであるため、詳細については上記のリソースを参照してください。

于 2011-08-27T12:17:08.043 に答える
5

Ajax 接続がまだアクティブなときに結果を確認するにはどうすればよいですか? jQuery の ajax 呼び出しの成功関数については認識していますが、接続中のデータを確認するにはどうすればよいですか?

実際、できます。上記の修正された回答を提供しましたが、まだ保留中か無視されているかはわかりません。正しい情報が利用できるように、ここで更新を提供します。

クライアントとサーバー間の接続を開いたままにしておくと、応答に追加される更新をプッシュできます。更新が発生するたびにXMLHttpRequest.onreadystatechangeイベントが発生し、の値はXMLHttpRequest.readyState3 になります。これは、XMLHttpRequest.responseText が成長し続けることを意味します。

この例をここで見ることができます: http://www.leggetter.co.uk/stackoverflow/7213549/

JS コードを表示するには、単にソースを表示します。PHPコードは次のとおりです。

<?php
$updates = $_GET['updates'];
if(!$updates) {
  $updates = 100;
}

header('Content-type: text/plain');
echo str_pad('PADDING', 2048, '|PADDING'); // initial buffer required

$sleep_time = 1;
$count = 0;
$update_suffix = 'Just keep streaming, streaming, streaming. Just keep streaming.';
while($count < 100) {
  $message = $count . ' >> ' . $update_suffix;
  echo($message);
  flush();
  $count = $count + 1;
  sleep($sleep_time);
}
?>

Firefox などの Gecko ベースのブラウザでは、responseTextを使用してを完全に置き換えることができmultipart/x-mixed-replaceます。この例は示していません。

を使用して同じ種類の機能を実現できるようには見えませんjQuery.ajax。イベントがsuccess発生するたびに、コールバックは発生しません。onreadystatechangeドキュメントには次のように記載されているため、これは驚くべきことです。

ただし、success、error、complete、および statusCode は考えられるすべての要件をカバーするため、onreadystatechange メカニズムは提供されません。

私が誤解していない限り、ドキュメントは間違っている可能性がありますか?

ここで jQuery を使用しようとする例を見ることができます: http://www.leggetter.co.uk/stackoverflow/7213549/jquery.html

Firebug または Chrome 開発者ツールのネットワーク タブを見ると、ファイル サイズがstream.php大きくなっていることがわかりますが、successコールバックはまだ起動していません。

于 2011-09-08T12:16:24.703 に答える