如何在websockets中始终保持连接打开状态

时间:2016-06-09 03:20:14

标签: scala websocket akka-http

服务器代码:

object EchoService {

  def route: Route = path("ws-echo") {
    get {
      handleWebSocketMessages(flow)
    }
  } ~ path("send-client") {
    get {
      sourceQueue.map(q => {
        println(s"Offering message from server")
        q.offer(BinaryMessage(ByteString("ta ta")))
      } )
      complete("Sent from server successfully")
    }
  }

  val (source, sourceQueue) = {
    val p = Promise[SourceQueue[Message]]
    val s = Source.queue[Message](100, OverflowStrategy.backpressure).mapMaterializedValue(m => {
      p.trySuccess(m)
      m
    })
    (s, p.future)
  }

  val flow =
    Flow.fromSinkAndSourceMat(Sink.ignore, source)(Keep.right)
}

客户代码:

object Client extends App {


  implicit val actorSystem = ActorSystem("akka-system")
  implicit val flowMaterializer = ActorMaterializer()

  val config = actorSystem.settings.config
  val interface = config.getString("app.interface")

  val port = config.getInt("app.port")


  // print each incoming strict text message
  val printSink: Sink[Message, Future[Done]] =
    Sink.foreach {
      case message: TextMessage.Strict =>
        println(message.text)

      case _ => println(s"received unknown message format")
    }

  val (source, sourceQueue) = {
    val p = Promise[SourceQueue[Message]]
    val s = Source.queue[Message](100, OverflowStrategy.backpressure).mapMaterializedValue(m => {
      p.trySuccess(m)
      m
    })
    (s, p.future)
  }

  val flow =
    Flow.fromSinkAndSourceMat(printSink, source)(Keep.right)


  val (upgradeResponse, sourceClosed) =
    Http().singleWebSocketRequest(WebSocketRequest("ws://localhost:8080/ws-echo"), flow)

  val connected = upgradeResponse.map { upgrade =>
    // just like a regular http request we can get 404 NotFound,
    // with a response body, that will be available from upgrade.response
    if (upgrade.response.status == StatusCodes.SwitchingProtocols || upgrade.response.status == StatusCodes.OK ) {
      Done
    } else {
      throw new RuntimeException(s"Connection failed: ${upgrade.response.status}")
    }
  }

  connected.onComplete(println)

}

当我点击http://localhost:8080/send-client时,我看到消息传到客户端但是一段时间后如果尝试再次发送给客户端,我在客户端看不到任何消息:s。我也试过source.concatMat(Source.maybe)(Keep.right)但没有运气:(

编辑:我使用js客户端进行了测试,不知何故连接/流量在服务器端关闭,无论如何都要阻止这个?以及如何在使用akka-http websocket客户端时收听此事件:s

1 个答案:

答案 0 :(得分:5)

  

您好,

     

它不保持连接的原因是因为默认情况下全部   默认情况下,HTTP连接启用idle-timeout以保持系统   如果客户在没有任何信号的情况下消失,则会泄漏连接。

     

克服这种限制的一种方法(实际上是我推荐的   方法)是在客户端注入保持活动消息   (服务器否则忽略的消息,但通知底层   连接仍然有效的HTTP服务器。

     

您可以将HTTP服务器配置中的空闲超时覆盖为   更大的价值,但我不建议这样做。

     

如果您使用的是基于流的客户端,请在何时注入心跳   必要的就像调用keepAlive并为其提供时间一样简单   您要注入的消息的间隔和工厂:   http://doc.akka.io/api/akka/2.4.7/index.html#akka.stream.scaladsl.Flow@keepAlive U>:输出:FlowOps.this.Repr [U]

     

该组合子将确保没有超过T的句号   沉默,因为如果有必要,它将注入元素以保持合同   (如果有足够的背景流量,则不会注入任何东西)

     

-Endre

谢谢你Endre :),工作片段..

// on client side 

 val (source, sourceQueue) = {
    val p = Promise[SourceQueue[Message]]
    val s = Source.queue[Message](Int.MaxValue, OverflowStrategy.backpressure).mapMaterializedValue(m => {
      p.trySuccess(m)
      m
    }).keepAlive(FiniteDuration(1, TimeUnit.SECONDS), () => TextMessage.Strict("Heart Beat"))
    (s, p.future)
  }