Remote Actors

I made a few patches to the example from http://dirkmeister.blogspot.com/2008/12/remote-actors-in-scala.html. It works with Scala 2.7.4RC1 on ubuntu 8.10. Milage may vary.

RemotePongApp must be started first.

RemotePingApp.scala:

package mgm7734
 
import scala.actors.Actor
import scala.actors.Actor._
import scala.actors.Exit
import scala.actors.remote.RemoteActor
import scala.actors.remote.RemoteActor._
import scala.actors.remote.Node
 
@serializable case object Ping
@serializable case object Pong
@serializable case object Quit
 
object RemotePingApp {
    def main(args: Array[String]) : Unit = {
        val port = 9001 // args(0).toInt
        val peer = Node("127.0.0.1", 9000) // Node(args(1), args(2).toInt)
        val ping = new RemotePing(port, peer, 16)
        ping.start()
    }
}
class RemotePing(port: Int, peer: Node, count: Int) extends Actor {
    trapExit = true // (1)
 
    def act() {
     RemoteActor.classLoader = getClass().getClassLoader()
    alive(port)     // (2)
    register('Ping, self) // (3)
 
    val pong = select(peer, 'Pong) // (4)
    link(pong)             // (5)
 
    var pingsLeft = count - 1
    pong ! Ping     // (6)
    while (true) {
      receive {
        case Pong =>
          Console.println("Ping: pong")
          if (pingsLeft > 0) {
            pong ! Ping
            pingsLeft -= 1
          } else {
            Console.println("Ping: start termination")
            pong ! Quit     // (7)
            // Terminate ping after Pong exited (by linking)
          }
        case Exit(pong, 'normal) => // (8)
            Console.println("Ping: stop")
            exit()
      }
    }
  }
}
 

RemotePongApp.scala:

package remote
<code>
import scala.actors.Actor
import scala.actors.Actor._
import scala.actors.remote.RemoteActor
import scala.actors.remote.RemoteActor._
 
object RemotePongApp {
    def main(args: Array[String]) : Unit = {
        val port = 9000 // args(0).toInt
        val pong = new RemotePong(port)
        pong.start()
    }
}
 
class RemotePong(port: Int) extends Actor {
  def act() {
    RemoteActor.classLoader = getClass().getClassLoader()
    alive(port)
    register('Pong, self)
 
    while (true) {
      receive {
        case Ping =>
          Console.println("Pong: ping")
          sender ! Pong
        case Quit =>
          Console.println("Pong: stop")
          exit()    // (9)
      }
    }
  }
}
 
  1. By setting trapExit, the linked actor is notified by sending an Exit(sender, reason) message. Otherwise the termination is either ignored (if reason is ‘normal) or the linked actor is terminated, too (reason != ‘normal).
  2. alive(port) (member of the RemoteActor object) starts the remote service listening on the given port
  3. register(symbol, actor) (member of the RemoteActor object) registers the given actor using the symbol. The other actors can then lookup the actor by the hostname and port and this symbol.
  4. This lookup is done by the select(node, symbol) method that returns an proxy actor, which managed the complete transmission.
  5. The link method links the Ping actor with the Pong actor, so that the current actor is notified if the Pong actor is terminated. This example shows that this also works remotely.
  6. That proxy actor is used to send messages to the remote node. Sending and receiving remote messages is similar to local messages. Well, everything must be serializable, but the use of case classes is recommended anyway. Here we send a Ping message to Pong
  7. The Quit message stops they Pong actor. See 9.
  8. When the Pong actor terminates, an Exit(sender, reason) message is sent to the Ping actor. This is linking system is used for error handling, here it is used to terminate the Ping actor, too.
  9. The Pong actor calls the exit() method, which terminates the actor with the reason ‘normal.
 
code/remoteactors.txt · Last modified: 2010/02/11 09:10
 
Recent changes RSS feed Valid XHTML 1.0 Driven by DokuWiki