2

そのストリーム上のデータをリッスンするためにバックエンド ソケットに接続するリアルタイム Web アプリケーションに play 2.0 を使用しています。

次の例は私が望むことを行いますが、クライアントの Web ページが閉じられているか、ページが変更されている場合にソケットを切断する方法がわかりません。

def comet = Action {

  val out = Enumerator.imperative[String]()
  val socketClient = new SocketClientModel("localhost", "testclient", 
    Option("username"), "password", out)
  socketClient.listen

  Ok.stream(out &> Comet(callback = "console.log"))
}

私が抱えている問題は、ページが閉じられているか変更されているときに socketClient.disconnect を呼び出す方法を考え出すことです。現在、ブラウザ セッションを閉じると、接続が確立され、サーバー側でデータが受信されていることがわかります。

4

1 に答える 1

4

ハッキーな解決策は、反対方向 (クライアントからサーバー) に ping を呼び出すことです。

  • 10 秒以内に接続がキャンセルされなかった場合に接続を破棄するタイマーを設定します (いつでもより長い期間を設定できます)。

    var timer; 
    
    def comet = Action {
         timer = Akka.system.scheduler.scheduleOnce(10 seconds) {
           socketClient.disconnect
         }
    ...
    }
    
  • ping を受信するアクションをセットアップし、javascript コードでタイマーをセットアップして、9 秒ごとにそのルートにリクエストを送信します。

    def keepAlive = Action {
        cancel.cancel
          timer = Akka.system.scheduler.scheduleOnce(10 seconds) {
              socketClient.disconnect
          }
    }
    

ユーザーが別のページに移動するか、comet アクションへの接続をキャンセルすると、クライアント側の ping タイマーもキャンセルする必要があります (ユーザーがページを変更した場合、これは自動的に行われるはずですが、ヘルスチェックが必要になります)同じページにとどまる場合はコメット接続で、など)。クライアントがアクションへの ping を停止すると、タイマーは最終的にソケットを強制終了します。

var2 つのアクション間で共有されるa を使用する必要があり、実際にはスレッドセーフではないため、これは非常に醜いです。また、サポートできるクライアントは 1 つだけです。しかし、あなたが与えたコード例は私が推測するものと同じです。複数のクライアントをサポートするには、どのセッションがどのソケットを開いているかを追跡する必要があります。ただし、ステートレスな動作は失われます。

よりクリーンな解決策は、小さなアクター システムを使用してこの動作をカプセル化することです。 t Stop メッセージを受け取ります。- また、KeepAlive メッセージを以前に受信していない限り、一定時間後に SocketActor に Stop メッセージを送信する KeepAliveActor もあります (つまり、ここで何が起こっているのか)。

コメット接続を受信すると、2 つの新しいアクターをスポーンし (2 つのアクターを非表示にしてメッセージを中継するためのマネージャー アクターが必要です)、それらへの参照をセッションにリンクしたままにします。キープアライブ アクションは、適切なセッションの参照をフェッチし、キープアライブ メッセージをアクターに送信します。

SocketActor は、Stop メッセージを受信すると、ソケットを閉じて、リンクされているアクターを破棄します。

もう少し複雑なコーディングなので、スニペットは含めませんが、単純な AKKA システムになるので、まだ慣れていない場合は、AKKA チュートリアルをチェックしてセットアップできるはずです。

于 2012-09-02T16:44:08.513 に答える