6

クライアントがこのようなphpファイルをリッスンする単純なサーバー送信イベントアプリを実装したい

<script src="eventsource.js"></script>
<script>
  var es = new EventSource('../sse.php');

  es.onmessage = function (event) {
    var data = JSON.parse(event.data);
    console.log('msg: ' + event.data);
  };

  es.onopen = function () {
    console.log('connected');
  }
</script>

しかし、メッセージをブロードキャストできる必要があり、接続されているすべてのクライアントが同時にメッセージを取得します。

phpファイルは別のリクエストによってトリガーされ、一部のSSEデータをすべてのクライアントに「エコー」します。

これは可能ですか?私が取ることができる別のルートはありますか?

前もって感謝します

4

4 に答える 4

7

PHPはこれには適していません。このイベントを待機しているクライアントが多数ある場合は、待機しているクライアントごとにPHPインタープリターのインスタンス(およびおそらくapacheスレッド)が必要になります。

あなたがやろうと思うかもしれないことは、イベント駆動型サーバーにこれを処理させることです。Node.JSとTornado(Python)は、私が過去に同様の状況で使用した2つの環境です。Node.jsを使用している場合は、socket.ioを調べて、サーバー送信イベントを使用しないことをお勧めしますが、必要なものは非常に単純になります。

2つのWebサーバーを並べて使用できます。現在のサーバー(Apacheを想定しています)と、更新を待機しているクライアントを処理するためにユーザーが作成したサーバーです。PHPサーバーが待機中のクライアントにメッセージを送信する場合は常に、PHPサーバーは他のサーバーに通知し(AMQP、ZeroMQ、Redis Pub / Sub、または非パブリックインターフェイスでの単純なHTTPリクエストがすべて適切な選択です)、そのサーバー待機中のクライアントにメッセージを渡します。

githubでnode.js+socket.io(SSEに簡単に置き換えることができます)を使用して、私が話していることの非常に単純なバージョンを見ることができます。

于 2013-01-08T21:07:29.050 に答える
1

重要な編集: (1日後)

テストした後、これはとても悪い解決策であることがわかりました。

テストケース:

  • クライアント:8つのクライアントを実行します(1つのブラウザー(Chromium、(k)ubuntu)、1つのタブ、8つのiframeで)。
  • サーバーAPI:Apache2.0ハンドラー
  • PHPバージョン5.3.10-1ubuntu3.4

結果:

6SSE接続が開かれました。ただし、2つのSSE接続は保留のままです。サーバーの他のページは、SSEクライアントを閉じるまで開くことができません。

ただし、サーバーはajaxによって多くのクライアントを処理できます(1秒ごとにajaxを繰り返します)。


古い答え:

共有メモリを使用します。

sse.php

<?php

header("Content-Type: text/event-stream\n\n");
header('Cache-Control: no-cache');

$key = "987654";
$permissions = 0666;
$size = 1024;

//Create or open the shared memory segment.
$segment = shm_attach($key, $size, $permissions);

$msg = ' null ';
$last_time = 0;
$time = 0;
while (1) {

    if (shm_has_var($segment, 0)) {
        $time = shm_get_var($segment, 0);
    }
    if (shm_has_var($segment, 0)) {
        $msg = shm_get_var($segment, 1);
    }
    $now = time();
    if ($last_time < $time) {
        $last_time = $time;
        echo 'data: msg(' . $msg . ') time(' . $time . ')';
        echo "\n\n";
    }

    ob_flush();
    flush();
    sleep(1);
}

trigger.php

<?php 
if (isset($_GET['msg'])) {

    $key = "987654";// TODO: how to generate suitable key?
    $permissions = 0666;
    $size = 1024;

    $segment = shm_attach($key, $size, $permissions);

    $time = time();
    $msg = $_GET['msg'];

    shm_put_var($segment, 0, $time);
    shm_put_var($segment, 1, $msg);
    echo $time;
}

この方法の欠点:

  1. 1秒の遅延
  2. 長時間開いている接続。これにより、スケーラビリティが低下します。

私の実装では、sse.phpは1秒以内に最後のメッセージのみを送信します。しかし、それを改善してデータベースを使用することができます。(trigger.phpが1秒間に3回呼び出された場合、最後のメッセージのみが保存されます)

于 2013-01-08T20:47:09.363 に答える
0

数の制限まで、それは同じサーバーへの接続のブラウザの制限数のためです、あなたは再構成によってそれを変えることができます。Firefoxにも同じデフォルト番号(6)があります。

また、サーバー側で切断イベントを処理する方法を考えています。SSEを使用するクライアントが多すぎると、他のサービスへのソケットなどの他のリソースを使用する場合でも、接続を管理する必要があります。

于 2013-08-19T23:13:44.637 に答える
-1

すべてのページが同時に同じメッセージを受け取ることはありません。

接続された後にのみメッセージを受け取ります。

必要に応じて、より「インスタント」メッセージングを可能にするWebSocketやNode.JSを調べることができます。

于 2013-01-07T19:22:20.497 に答える