客户端关闭Web套接字连接时停止Akka流源

时间:2019-01-08 18:24:38

标签: scala websocket akka akka-stream akka-http

我有一个akka http web socket Route,其代码类似于:

priv val wsReader:路线=     path(“ v1” /“ data” /“ ws”){       log.info(“正在打开正在连接的网络套接字...”)

  val testSource = Source
    .repeat("Hello")
    .throttle(1, 1.seconds)
    .map(x => {
      println(x)
      x
    })
    .map(TextMessage.Strict)
    .limit(1000)

  extractUpgradeToWebSocket { upgrade ⇒
    complete(upgrade.handleMessagesWithSinkSource(Sink.ignore, testSource))
  }
}

一切正常(我每秒从客户端收到1条测试消息)。唯一的问题是,如果客户端关闭Web套接字连接,我不了解如何停止/关闭SourcetestSource)。

即使Web套接字关闭,您也可以看到源继续生成元素(请参见println)。

如何检测客户端断开连接?

2 个答案:

答案 0 :(得分:1)

一种方法是使用KillSwitches处理testSource关闭。

private val wsReader: Route =
path("v1" / "data" / "ws") {
  logger.info("Opening websocket connecting ...")

  val sharedKillSwitch = KillSwitches.shared("my-kill-switch")

  val testSource =
    Source
     .repeat("Hello")
     .throttle(1, 1.seconds)
     .map(x => {
       println(x)
       x
     })
    .map(TextMessage.Strict)
    .limit(1000)
    .via(sharedKillSwitch.flow)

  extractUpgradeToWebSocket { upgrade ⇒
    val inSink = Sink.onComplete(_ => sharedKillSwitch.shutdown())
    val outSource = testSource
    val socket = upgrade.handleMessagesWithSinkSource(inSink, outSource)

    complete(socket)
  }
}

答案 1 :(得分:1)

handleMessagesWithSinkSource实现为:

/**
 * The high-level interface to create a WebSocket server based on "messages".
 *
 * Returns a response to return in a request handler that will signal the
 * low-level HTTP implementation to upgrade the connection to WebSocket and
 * use the supplied inSink to consume messages received from the client and
 * the supplied outSource to produce message to sent to the client.
 *
 * Optionally, a subprotocol out of the ones requested by the client can be chosen.
 */
def handleMessagesWithSinkSource(
  inSink:      Graph[SinkShape[Message], Any],
  outSource:   Graph[SourceShape[Message], Any],
  subprotocol: Option[String]                   = None): HttpResponse =

  handleMessages(Flow.fromSinkAndSource(inSink, outSource), subprotocol)

这意味着接收器和源是独立的,实际上,即使客户端关闭了连接的传入端,源也应该继续生成元素。但是,当客户端完全重置连接时,它应该停止。

要在传入连接关闭后立即停止生成传出数据,可以使用Flow.fromSinkAndSourceCoupled,因此:

val socket = upgrade.handleMessages(
  Flow.fromSinkAndSourceCoupled(inSink, outSource)
  subprotocol = None
)