【发布时间】:2015-06-01 07:27:39
【问题描述】:
我正在尝试使用akka Actor 设置一个简单的 TCP 服务器,它应该允许同时连接多个客户端。我将问题简化为以下简单程序:
package actorfail
import akka.actor._, akka.io._, akka.util._
import scala.collection.mutable._
import java.net._
case class Foo()
class ConnHandler(conn: ActorRef) extends Actor {
def receive = {
case Foo() => conn ! Tcp.Write(ByteString("foo\n"))
}
}
class Server(conns: ArrayBuffer[ActorRef]) extends Actor {
import context.system
println("Listing on 127.0.0.1:9191")
IO(Tcp) ! Tcp.Bind(self, new InetSocketAddress("127.0.0.1", 9191))
def receive = {
case Tcp.Connected(remote, local) =>
val handler = context.actorOf(Props(new ConnHandler(sender)))
sender ! Tcp.Register(handler)
conns.append(handler)
}
}
object Main {
def main(args: Array[String]) {
implicit val system = ActorSystem("Test")
val conns = new ArrayBuffer[ActorRef]()
val server = system.actorOf(Props(new Server(conns)))
while (true) {
println(s"Sending some foos")
for (c <- conns) c ! Foo()
Thread.sleep(1000)
}
}
}
它绑定到 localhost:9191 并接受多个连接,将连接处理程序添加到全局数组并定期将字符串 "foo" 发送到每个连接。现在,当我尝试同时连接多个客户端时,只有第一个客户端获得“foo”。当我打开第二个连接时,它不会发送任何 foo,而是收到以下类型的日志消息:
Sending some foos
[INFO] [03/27/2015 21:24:07.331] [Test-akka.actor.default-dispatcher-6] [akka://Test/deadLetters] Message [akka.io.Tcp$Write] from Actor[akka://Test/user/$a/$b#-308726290] to Actor[akka://Test/deadLetters] was not delivered. [7] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
我了解这意味着我们尝试向其发送Tcp.Write 命令的目标参与者不再接受消息。但这是为什么呢?你能帮我理解根本问题吗?我怎样才能做到这一点?
【问题讨论】:
-
演员内的可变状态很好,但看起来您正试图从演员外部访问服务器演员的连接。这不是很Akka-y。为什么不让服务器管理连接池并在这些连接上发送消息?
-
@Gangstead 我刚刚测试了使用演员发送 Foos 并且这似乎有效,您能否详细说明此技术方面或记录在哪里?我希望实际上有一种方法可以将参与者与其他并发模型混合在一起。实际上,从外部访问参与者的代码是以阻塞方式从
Source读取行的循环。当然,我可以将其转换为演员,但将其表述为状态机会有点笨重。我宁愿有一种从外部发送消息的方法,只给 ActorRef。 -
你从 Akka 项目的负责人那里得到了答案。他提供了一些文档链接。我认为您不能像希望的那样混合并发模型。
-
@Gangstead 好吧,根据他的回答我可以:)