Webサーバーとブラウザ間の双方向通信は目新しいものではありません。あなたが読んでいる質問に新しい答えが投稿された場合、StackOverflowは今日それを行います。既存のテクノロジーを使用してソケットスタイルの動作を実装するには、いくつかの異なる戦略があります。
- AJAXショートポーリング:サーバーに接続し、新しいメッセージがあるかどうかを確認します。そうでない場合は、すぐに切断し、しばらくしてからもう一度質問してください。これは、長時間実行されているアイドル状態の接続をサーバーに開いたままにしたくない場合に便利ですが、新しいメッセージはポーリング間隔と同じ速さでしか受信されず、確立のオーバーヘッドが発生します。ポーリングするたびに新しいHTTP接続。
- AJAXロングポーリング:サーバーに接続し、新しいメッセージが利用可能になるまで接続を開いたままにします。これにより、新しいメッセージを高速に配信し、HTTP接続の頻度を減らすことができますが、サーバー上でより長時間実行されるアイドルプロセスが発生します。
- Iframeロングポーリング:上記と同じですが、XHRオブジェクトの代わりに非表示のiframeを使用します。クロスサイトのロングポーリングを実行する場合に、同一生成元ポリシーを回避するのに役立ちます。
- プラグイン:FlashのXMLSocket、Javaアプレットなどを使用して、ブラウザの実際の低レベルの永続ソケットに近いものを確立できます。
HTML5ソケットは、利用可能な基本的な戦略を実際には変更しません。ほとんどの場合、それらはすでに使用されている戦略を形式化するだけであり、永続的な接続を明示的に識別して、よりインテリジェントに処理できるようにします。モバイルブラウザへのWebベースのプッシュメッセージングを実行したいとします。通常のロングポーリングでは、接続を維持するためにモバイルデバイスはスリープ状態を維持する必要があります。WebSocketを使用すると、モバイルデバイスがスリープ状態になりたいときに、プロキシへの接続を渡すことができ、プロキシが新しいデータを受信すると、デバイスをウェイクアップしてメッセージを返すことができます。
サーバー側は広く開かれています。短いポーリングアプリケーションのサーバー側を実装するには、ある種の時系列のメッセージキューが必要です。クライアントが接続すると、新しいメッセージをキューからシフトするか、オフセットを渡して、オフセットよりも新しいメッセージを読み取ることができます。
サーバー側のロングポーリングを実装すると、選択肢が狭まり始めます。ほとんどのHTTPサーバーは、接続、リソースの要求、切断という短期間の要求用に設計されています。300人が10分でサイトにアクセスし、それぞれが接続してHTTPリソースをダウンロードするのに2秒かかる場合、サーバーは常に平均1つのHTTP接続を開いています。長いポーリングアプリを使用すると、突然300倍の接続を維持できます。
独自の専用サーバーを実行している場合はこれを処理できる可能性がありますが、共有ホスティングプラットフォームでは、リソースの制限にぶつかる可能性があり、AppEngineも例外ではありません。App Engineは、短いポーリングなど、大量の低レイテンシリクエストを処理するように設計されています。App Engineで長いポーリングを実装することはできますが、お勧めできません。30秒を超えて実行されるリクエストは終了し、実行時間の長いプロセスはCPUクォータを使い果たします。
これに対するAppEngineのソリューションは、今後のChannelAPIです。チャネルAPIは、Googleの既存の堅牢なXMPPインフラストラクチャを使用して長いポーリングを実装します。
BrettBavarとMoisheLettvinのGoogleI/ Oトークでは、使用パターンを次のように説明しています。
App Engineアプリは、リモートサーバー上にチャネルを作成し、チャネルIDを返します。このIDはWebブラウザーに渡されます。
class MainPage(webapp.RequestHandler):
def get(self):
id = channel.create_channel(key)
self.response.out.write(
{'channel_id': id})
WebブラウザはチャネルIDを同じリモートサーバーに渡し、iframeロングポーリングを介して接続を確立します。
<script src='/_ah/channel/jsapi'></script>
<script>
var channelID = '{{ channel_id }}';
var channel =
new goog.appengine.Channel(channelId);
var socket = channel.open();
socket.onmessage = function(evt) {
alert(evt.data);
}
</script>
何か面白いことが起こったとき、App Engineアプリはユーザーのチャンネルにメッセージをプッシュでき、ブラウザーの長いポーリングリクエストはすぐにそれを受信します。
class OtherPage(webapp.RequestHandler):
def get(self):
# something happened
channel.send_message(key, 'bar')