我正在将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。目前,当我关闭浏览器会话时,我仍然可以看到已建立连接并且正在服务器端接收数据。
答案 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教程来设置它,如果你还没有习惯它。