假设我有一个能够通过TCP发送和接收消息的IO Actor connection
。在我的演员中,我问连接的另一方是否有回应:
connection.ask(ByteString("stuff")).collect {
case Received(response) => log.debug(response.utf8String)
}
看来,使用此代码,ask将会超时,而包含的actor会在ask模式之外接收原始消息。
你能和Akka IO演员一起使用ask模式吗?如果没有,为什么不呢?
答案 0 :(得分:2)
我不太详细了解这个架构,但是我会在这里向自己解释:
这里的Akka IO连接器演员的问题是他们不能以请求 - 响应的方式工作。如果你考虑一下 - 这是有道理的,因为TCP不是一个请求 - 响应协议。 TCP甚至没有消息的概念。从程序员的角度来看,TCP连接只是一对连续的字节流 - 每个方向一个。那就是它。
Akka IO是网络协议之上的最小角色层,因此它模仿这种行为并不奇怪。当TCP actor从网络接收一些数据时,它只知道一件事 - 它应该向最初发送Received
消息的actor发送Connect
消息。这就是全部。它不知道从网络收到的数据与您之前发送的数据有某种关系。
除此之外,ask
模式仅在假设当您向某个actor发送消息A
时才会起作用,它会通过将消息B
发送到消息A
的发件人。我们已经知道,TCP演员不会这样做 - 它只是将所有内容发送给原始Connect
消息的发件人。
需要这种假设的原因是ask
模式实际上创造了某种类型的幻象"设置为使用ask
发送的邮件的发件人的actor。这个"幻像"然后,actor将收到响应并调用Future
上注册的所有回调。作为旁注 - 请注意,这些回调完全独立于发送方调用,即它们可以同时运行!
所以,我最后会得出结论,像这样使用的ask
模式将不与Akka IO一起工作,因为它对于这样的抽象来说太低了。如果您仍然想要它,您需要在Akka IO之上创建自己的抽象层,例如:一个简单的中间actor,它涵盖TCP连接器actor并实现请求 - 响应行为。
答案 1 :(得分:0)
作为对@ ghik回答的补充参考,这里大致说明了我是如何创建一个中间角色来为我的其他演员启用IO的问题模式。
class IOAskHandlerActor(address: InetSocketAddress) extends Actor {
override def receive = {
// Connection setup code omitted
case Connected(remote, local) =>
// other code omitted
context become latch(sender())
}
def latch(connection: ActorRef): Receive = {
case outgoing =>
context become receiving(connection, sender())
connection ! MySerializer.write(outgoing)
}
def receiving(connection: ActorRef, asker: ActorRef): Receive = {
case Received(incoming) =>
context become latch(connection)
asker ! MySerializer.read(incoming)
}
}
此类的实例可以ask
用于回复。请注意,我仅使用一个同时提问者(这是我的用例)对此进行了测试,这可能对多个问题无效。