简体   繁体   English

将简单的Scala远程actor示例移植到Akka actor

[英]Porting simple Scala remote actor example to Akka actors

I try to port this simple actor example of sending "Ping" and "Pong" from Scala actors to Akka actors, but I keep getting errors and I wonder if it is just a simple error or some fundamental fault. 我尝试移植这个简单的演员示例 ,从Scala演员发送“Ping”和“Pong”到Akka演员,但我不断收到错误,我想知道这只是一个简单的错误或一些基本的错误。

Consider this code: 考虑以下代码:

import akka.actor.Actor._
import akka.actor.Actor

case class Message(text: String)

class PingPongActor(name: String) extends Actor {

  def receive = {
      case Message(msg) =>
        println("received: " + msg)
        Thread.sleep(1000)
        self.reply(Message("Ping"))
      case None => println("ping: timed out!")
  }
}

object Ping extends App {
  remote.start("localhost", 2552)
        .register("ping-service", actorOf(new PingPongActor("pong")))

  val actor = remote.actorFor("ping-service", "localhost", 2552)

  actor ! (Message("Ping"))
}

object Pong extends App {
  remote.start("localhost", 2553)
        .register("pong-service", actorOf(new PingPongActor("ping")))

  val actor = remote.actorFor("pong-service", "localhost", 2553)

  actor ! (Message("Pong"))
}

I keep getting this error: 我一直收到这个错误:

received: Ping
[GENERIC] [07.10.11 23:18] [RemoteServerStarted(akka.remote.netty.NettyRemoteSupport@3ff2cea2)]
[ERROR]   [07.10.11 23:18] [akka:event-driven:dispatcher:global-2] [LocalActorRef] 
   No sender in scope, can't reply.
   You have probably:
      1. Sent a message to an Actor from an instance that is NOT an Actor.
      2. Invoked a method on an TypedActor from an instance NOT an TypedActor.
   You may want to have a look at safe_! for a variant returning a Boolean
akka.actor.IllegalActorStateException: 
   No sender in scope, can't reply.
   You have probably:
      1. Sent a message to an Actor from an instance that is NOT an Actor.
      2. Invoked a method on an TypedActor from an instance NOT an TypedActor.
   You may want to have a look at safe_! for a variant returning a Boolean
[laptop_e3263500-f129-11e0-a78d-001636ff8076]
    at akka.actor.NullChannel$.$bang(Channel.scala:177)
    at akka.actor.ActorRef$class.reply(ActorRef.scala:398)
    at akka.actor.LocalActorRef.reply(ActorRef.scala:605)
    at PingPongActor$$anonfun$receive$1.apply(RemoteActor.scala:21)
    at PingPongActor$$anonfun$receive$1.apply(RemoteActor.scala:15)
    at akka.actor.Actor$class.apply(Actor.scala:545)
    at PingPongActor.apply(RemoteActor.scala:13)

The idea is that I start up two applications, Ping and Pong which try to send a message to each other every second and print it on the terminal (or print an error message if no message is received for two seconds). 我的想法是启动两个应用程序, PingPong ,它们尝试每秒向对方发送一条消息并在终端上打印(如果两秒钟没有收到消息则打印错误消息)。

The biggest fundamental problem with your code is that you're sending the message from outside of an actor and so the response has no where to go. 您的代码最大的根本问题是您从演员之外发送消息,因此响应无处可去。 You'll notice in the original example, the initial Message("ping") is sent from within the act() loop of the Ping actor. 您将注意到在原始示例中,初始Message("ping")是从Ping actor的act()循环内发送的。 But really you have a couple of issues and it's better to start over, restructuring the code a bit. 但实际上你有几个问题,最好重新开始,重新调整一下代码。 Here's an example that works, but it depends on starting the clients in a particular order. 这是一个有效的示例,但它取决于以特定顺序启动客户端。 Of course, you can rewrite this to keep retrying the connection from PingActor, among other things. 当然,您可以重写此操作以继续从PingActor重试连接等。

sealed trait Message
case class Ping extends Message
case class Pong extends Message

class PingActor extends Actor {

  override def preStart = {
    val pong = remote.actorFor("pong-service", "localhost", 2553)
    pong ! Ping
  }

  def receive = {
    case Pong => {
      println("Received pong")
      Thread.sleep(1000)
      self.reply(Ping)
    }
  }
}

class PongActor extends Actor {
  def receive = {
    case Ping => {
      println("Received ping")
      Thread.sleep(1000)
      self.reply(Pong)
    }
  }
}

object pingApp extends App {
  val actor = actorOf(new PingActor)
  remote.start("localhost", 2552)
        .register("ping-service", actor)
}

object pongApp extends App {
  val actor = actorOf(new PongActor)
  remote.start("localhost", 2553)
        .register("pong-service", actor)
}

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

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