如何创建仅使用akka流消耗消息的TCP接收器?

时间:2015-07-22 15:24:24

标签: scala-2.11 akka-stream

我们正在:akka-stream-experimental_2.11 1.0。

example

的启发

我们写了一个TCP接收器如下:

def bind(address: String, port: Int, target: ActorRef)
          (implicit system: ActorSystem, actorMaterializer: ActorMaterializer): Future[ServerBinding] = {
    val sink = Sink.foreach[Tcp.IncomingConnection] { conn =>
      val serverFlow = Flow[ByteString]
        .via(Framing.delimiter(ByteString("\n"), maximumFrameLength = 256, allowTruncation = true))
        .map(message => {
        target ? new Message(message); ByteString.empty
      })
      conn handleWith serverFlow
    }

    val connections = Tcp().bind(address, port)
    connections.to(sink).run()
  }

但是,我们的目的是让接收器完全不响应并且只接收消息。 (TCP消息发布者不关心响应)。

甚至可能吗?因为akka.stream.scaladsl.Tcp.IncomingConnection采用以下类型的流来完全不响应:Flow [ByteString,ByteString,Unit]

如果是,将非常感谢一些指导。提前谢谢。

以下一次尝试通过我的单元测试,但不确定它是否是最好的主意:

def bind(address: String, port: Int, target: ActorRef)
          (implicit system: ActorSystem, actorMaterializer: ActorMaterializer): Future[ServerBinding] = {
    val sink = Sink.foreach[Tcp.IncomingConnection] { conn =>

      val targetSubscriber = ActorSubscriber[Message](system.actorOf(Props(new TargetSubscriber(target))))

      val targetSink = Flow[ByteString]
        .via(Framing.delimiter(ByteString("\n"), maximumFrameLength = 256, allowTruncation = true))
        .map(Message(_))
        .to(Sink(targetSubscriber))

      conn.flow.to(targetSink).runWith(Source(Promise().future))
    }

    val connections = Tcp().bind(address, port)
    connections.to(sink).run()
  }

1 个答案:

答案 0 :(得分:1)

你走在正确的轨道上。为了在某​​些时候保持关闭连接的可能性,您可能希望保留承诺并在以后完成它。一旦元素完成,该元素由源发布。但是,由于您不希望在连接上发布任何元素,因此您可以使用drop(1)确保源永远不会发出任何元素。

这是您的示例的更新版本(未经测试):

val promise = Promise[ByteString]()
// this source will complete when the promise is fulfilled
// or it will complete with an error if the promise is completed with an error
val completionSource = Source(promise.future).drop(1)

completionSource  // only used to complete later
  .via(conn.flow) // I reordered the flow for better readability (arguably)
  .runWith(targetSink)

// to close the connection later complete the promise:
def closeConnection() = promise.success(ByteString.empty) // dummy element, will be dropped

// alternatively to fail the connection later, complete with an error
def failConnection() = promise.failure(new RuntimeException)