使用持久连接播放2.0 Comet

时间:2012-08-17 20:02:24

标签: scala playframework playframework-2.0

我正在将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。目前,当我关闭浏览器会话时,我仍然可以看到已建立连接并且正在服务器端接收数据。

1 个答案:

答案 0 :(得分:3)

一个hacky解决方案可能是你在另一个方向(客户端到服务器)进行ping调用:

  • 您设置了一个计时器,如果在10秒之前没有取消连接,则会破坏该连接(您可以始终设置更长的时间段):

    var timer; 
    
    def comet = Action {
         timer = Akka.system.scheduler.scheduleOnce(10 seconds) {
           socketClient.disconnect
         }
    ...
    }
    
  • 您设置了一个Action,它接收ping并在javascript代码中设置一个计时器,每隔9秒向该路由发送一次请求:

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

当用户转到另一个页面,或取消与彗星Action的连接时,它也应取消客户端的ping计时器(如果用户更改页面,这应该是自动的,但你必须有如果你留在同一页面等,请对彗星连接进行一些健康检查。)当客户端停止ping您的操作时,计时器最终会终止套接字。

这真的很丑,因为你需要使用在你的两个动作之间共享的var并且它不是真正的线程安全的。它也只能支持一个客户端。但是你给出的代码示例与我猜的相同。您需要跟踪哪个会话已打开哪个套接字以支持多个客户端。你会失去无国籍的行为。

更清洁的解决方案是使用小型actor系统来封装此行为:    - 你有一个SocketActor,当它收到一个Start消息时,打开一个套接字并在PushEnumerator上推送东西,只要它没有收到Stop消息,它就会继续这样做。    - 你还有一个KeepAliveActor,它会在给定的时间后向SocketActor发送一条Stop消息,除非它之前收到了KeepAlive消息(所以,这里发生了什么)。

当你收到一个彗星连接时,你会产生两个新的演员(你应该有一个经理演员来隐藏这两个演员并转发消息等)并保持一个链接到会话的引用。然后,keepalive动作将获取正确会话的ref并将KeepAlive消息发送给actor。

当SocketActor收到Stop消息时,会关闭套接字并销毁链接到他的actor。

这是一个更复杂的编码,所以我不包括片段,但它将是一个简单的AKKA系统,所以你应该能够通过查看AKKA教程来设置它,如果你还没有习惯它。