PHPでの長いポーリングメカニズムの簡単な実装

ウィキペディアによると、現在、Cometテクノロジーの使用は非常に人気があります。「一定のHTTP接続により、Webサーバーがブラウザーからの追加要求なしにブラウザーにデータを送信(プッシュ)できるようになるとき」。

この技術にはさまざまな実装がありますが、ここではそのうちの1つ、つまりロングポーリングと呼ばれるものについて詳しく説明します。 記事では、それが何であり、何で食べられるかを分析します。

さて、サードパーティ製のソフトウェアを使用しない実装(PHPのみ)を見るのは面白いかもしれないことを知っている人のために。 PHPスクリプトよりもはるかに高い負荷に耐えることができる特別な彗星サーバーがある場合、なぜこれが必要なのでしょうか? これは、高負荷なしで小規模なプロジェクトを作成する必要があり、ホスティング時にサードパーティソフトウェアをインストールできない場合に便利です。 サードパーティのアプリケーションを使用することが不可能な1つのタスクのフレームワーク内で、この機能を実装する必要がある場合は、共有しないでください。



理論


ロングポーリングとは何ですか?

次のようになります。

1)クライアントは通常のajaxリクエストをサーバーに送信します

2)サーバーは、このリクエストを迅速に処理してクライアントに応答を送信する代わりに、サイクルを開始し、各反復でイベント(別のクライアントがレコードを追加または削除)を監視します。

3)イベントが発生すると、サーバーは応答を生成してクライアントに送信し、要求を完了します。

4)サーバーからの応答を受信したクライアントは、イベントハンドラーを開始し、同時に別の「長い」要求をサーバーに送信します。



つまり、すべてが非常にシンプルで明確です。 ただし、実装には対処する必要があるいくつかの問題があります。



練習する手順




まず、スクリプトが相互にどのように相互作用するかという疑問が生じます。 実際、サーバーへの各クライアント要求に対して、PHPスクリプトの独立したコピーが作成されます。 つまり、イベントデータを保存するには、何らかの種類の共有メモリが必要です。

従来のオプションは、イベントで動作し、クライアントとの接続を維持するデーモンを実行することです。 デーモンを使用すると、メモリの問題が自然に解決します。 クライアントは、イベントを受信するためにWebサーバーではなく、デーモンを使用します。 同時に、イベントを開始したクライアントは、イベントが発生したこともデーモンに通知します。 そして、すべてがこの悪魔の記憶の中で回転します。 一般的には何でも書くことができます。

しかし、私たちにとって、1か所で縫うことと、サードパーティのアプリケーションなしでやりたいという願望の観点から、悪魔は何もしません。 また、私の好みでは、PHPでデーモンを作成することはあまり面白くありません。 ホスティング事業者は、スクリプトの最大実行時間を変更する際に問題を抱えている可能性があります。また、このデーモンとクライアントとのやり取りのためのインターフェースについても検討します。

残っているのは、PHP自体に共有メモリを実装する方法を決定することです。 ファイルやデータベースにイベントを保存するためのオプションが思い浮かびますが、私は何かをもっと密接にしたい-メモリ内に。 残念ながら、Memcacheは利用できませんが、それではどうすればよいでしょうか? また、PHPには共有メモリなどの機能があります。より正確には、この概念はこの言語の機能ではありませんが、使用する機会を与えてくれます。 このテクノロジーのメカニズムにより、RAMにセルを作成し、それを独自の目的に使用できます。 ここで使用します。



練習する


必要な機能を実装するクラスインターフェイスを導入してみましょう。

どのような方法が必要ですか?

1)当然、クライアントがポーリング要求を送信するときに呼び出され、発生するイベントを監視する「盗聴」メソッド。 このlistenメソッドを呼び出しました。

2)さらに、イベントを作成するメソッドが必要です。 このメソッドはpushと呼ばれます。

3)結果をクライアントに送信する前にイベントデータを処理する可能性があります。 したがって、イベントを登録し、ハンドラーをそれに関連付けるメソッドを追加しました。 registerEventメソッドが呼び出されます。



その結果、次のクラスインターフェイスが取得されます。

class Polling { /** *   * @param string $event   * @param array $data   */ public function push($event, $data = null); /** * ""  .      max_execution_time * @param int $lastQueryTime      "". *    ,      ,  *  .   ,        * @return array         */ public function listen($lastQueryTime = null); /** *     .      . * @param string $event   * @param callback $callback - */ public function registerEvent($event, $callback); }
      
      







いくつかのメモ:

1) registerEventメソッドでは、イベントごとに1つのハンドラーのみがサポートされます。これは、ハンドラーによって返される値がイベントデータとしてクライアントに返されるためです。 1つのハンドラーで、いくつかの関数を呼び出し、それらの作業の結果からクライアントへの応答を収集できます。 ただし、コードをやり直して、複数のハンドラーをサポートするのにそれほど困難はありません。

2) listenメソッドは、 lastQueryTimeパラメーターを使用します。これにより、 listen要求を受信する前に発生したイベントを処理できます。 これは、ネットワークの負荷が高く、クライアントからの1つのポーリング要求の完了から別のポーリング要求の開始までにかなりの時間が経過する場合に役立ちます。

3)上記のコードは、メモリへの同時アクセスを考慮していません。 しかし、一般的に。 より信頼性の高い作業を行うには、セマフォを使用することが望ましいです。

4) listenメソッドは、 sleep(1)関数の呼び出しを使用します。 これは、アイドル反復の回数を減らすために必要です。 リアルタイムをシミュレートするには、1秒に1回のリフレッシュレートで十分です。



まあ、クライアントではすべてが非常に簡単です。 ポーリング要求をサーバーに送信し、応答を待機し、イベントハンドラーを開始して、要求を再送信するメソッドが必要です。 さて、イベントハンドラー自体を登録するメソッド。



ソース:

PHPで説明されているPollingクラス

誰かがそれを必要とするなら、私はそれを整理してクライアント部分をレイアウトします。



All Articles