2

我正在将 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

一个 hacky 解决方案可能是让您在另一个方向(客户端到服务器)进行 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
          }
    }
    

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

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

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

当你收到一个彗星连接时,你会产生两个新的演员(你应该有一个经理演员来隐藏这两个演员并中继消息等)并保持他们的参考链接到会话。然后,keepalive 操作将获取正确会话的 ref 并将 KeepAlive 消息发送给参与者。

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

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

于 2012-09-02T16:44:08.513 回答