简体   繁体   English

Akka Stream,Tcp().bind,当客户端关闭socket时处理

[英]Akka Stream, Tcp().bind, handle when the client close the socket

I'm quite new in Akka Stream and I'd like to learn how handle a TCP socket for a project of mine.我是 Akka Stream 的新手,我想了解如何为我的项目处理 TCP 插座。 I took this piece of code from the Akka Stream official documentation .我从Akka Stream 官方文档中获取了这段代码。

import akka.stream.scaladsl.Framing

val connections: Source[IncomingConnection, Future[ServerBinding]] =
  Tcp().bind(host, port)

connections.runForeach { connection =>
  println(s"New connection from: ${connection.remoteAddress}")

  val echo = Flow[ByteString]
    .via(Framing.delimiter(ByteString("\n"), maximumFrameLength = 256, allowTruncation = true))
    .map(_.utf8String)
    .map(_ + "!!!\n")
    .map(ByteString(_))

  connection.handleWith(echo)
}

If I connect from the terminal using netcat I can see that the Akka Stream TCP socket works as expected.如果我使用 netcat 从终端连接,我可以看到 Akka Stream TCP 套接字按预期工作。 I also found out that If I need to close the connection using an user message, I can use a takeWhile as follow我还发现如果我需要使用用户消息关闭连接,我可以使用takeWhile如下

import akka.stream.scaladsl.Framing

val connections: Source[IncomingConnection, Future[ServerBinding]] =
  Tcp().bind(host, port)

connections.runForeach { connection =>
  println(s"New connection from: ${connection.remoteAddress}")

  val echo = Flow[ByteString]
    .via(Framing.delimiter(ByteString("\n"), maximumFrameLength = 256, allowTruncation = true))
    .map(_.utf8String)
    .takeWhile(_.toLowerCase.trim != "exit")   // < - - - - - - HERE
    .map(_ + "!!!\n")
    .map(ByteString(_))

  connection.handleWith(echo)
}

What I can't find is how to manage a socket closed by a CMD + C action.我找不到的是如何管理由CMD + C操作关闭的套接字。 Akka Stream use Akka.io to manage the TCP connection internally, so it must send some of its PeerClose messages when the socket is closed. Akka Stream use Akka.io to manage the TCP connection internally, so it must send some of its PeerClose messages when the socket is closed. So, my understanding of Akka.io tells me that I should receive a feedback from the socket closing but I can't find how to do that with Akka Stream. So, my understanding of Akka.io tells me that I should receive a feedback from the socket closing but I can't find how to do that with Akka Stream. Is there a way to manage that?有没有办法管理它?

connection.handleWith(echo) is syntactic sugar for connection.flow.joinMat(echo)(Keep.right).run() which will have the materialized value of echo , which is generally not useful. connection.handleWith(echo)connection.flow.joinMat(echo)(Keep.right).run()的语法糖,它将具有echo的具体化值,这通常没有用。 Flow.via.map.takeWhile has NotUsed as a materialized value, so that's also basically useless. Flow.via.map.takeWhileNotUsed作为物化值,所以这也基本上没用。 However, you can attach stages to echo which will materialize differently.但是,您可以将阶段附加到以不同方式实现的echo

One of these is .watchTermination :其中之一是.watchTermination

connections.runForeach { connection =>
  println(s"New connection from: ${connection.remoteAddress}")

  val echo: Flow[ByteString, ByteString, Future[Done]] = Flow[ByteString]
    .via(Framing.delimiter(ByteString("\n"), maximumFrameLength = 256, allowTruncation = true))
    .map(_.utf8String)
    .takeWhile(_.toLowerCase.trim != "exit")   // < - - - - - - HERE
    .map(_ + "!!!\n")
    .map(ByteString(_))
    // change the materialized value to a Future[Done]
    .watchTermination()(Keep.right)

  // you may need to have an implicit ExecutionContext in scope, e.g. system.dispatcher,
  //  if you don't already
  connection.handleWith(echo).onComplete {
    case Success(_) => println("stream completed successfully")
    case Failure(e) => println(e.getMessage)
  }
}

This will not distinguish between your side or the remote side closing the connection normally;这将无法区分您端或远程端是否正常关闭连接; it will distinguish the stream failing.它将区分 stream 失败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM