16
votes

Using Scala with Akka IO is there a way to have an Actor strictly for listening and then when a connection is established create a new actor that will then be responsible for that Socket (Reading, Writing, etc)?

So far I have this. The problem is that the Server actor is receiving the data. I would like to transfer ownership of the socket to the new created Client actor so that it receives any messages related to the socket. Anyone know how to do that?

Edit: added solution. I just needed to pass the ActorRef into the curried parameter of accept

import akka.actor._
import akka.actor.IO.SocketHandle
import java.net.InetSocketAddress


/**
 * Purpose:
 * User: chuck
 * Date: 17/01/13
 * Time: 5:37 PM
 */
object Main {

  class Server extends Actor {

    override def preStart() {
      IOManager(context.system) listen new InetSocketAddress(3333)
    }

    def receive = {

      case IO.NewClient(server) =>

        val client = context.actorOf(Props(new Client()))
        server.accept()(client)
        println("Client accepted")

      case IO.Read(socket, bytes) =>
        println("Server " + bytes)


    }
  }

  class Client() extends Actor {

    def receive = {

      case IO.Read(socket, bytes) =>
        println("Client " + bytes)

      case IO.Closed(socket, reason) =>
        println("Socket closed " + reason)

    }

  }

  def main(args: Array[String]) {
    val system = ActorSystem()
    system.actorOf(Props(new Server))
  }

}

Thanks!

1
what have your tried? what is the exact problem?om-nom-nom
Just figured it out val socket = server.accept() needs to be val socket = server.accept()(client) where client is the newly created actortkblackbelt
There is work going on on a new IO layer that the Akka team designed in collaboration with the spray.io team that will be much more flexible. You might want to look into that when it comes out.Endre Varga
Thanks for the tip. Seems really cool.tkblackbelt
If you have a solution, you should make it an answer and accept it so we know it is solved.mor

1 Answers

3
votes

To make the answer a little more visible :

From the Akka documentation for ServerHandle :

def accept ()(implicit socketOwner: ActorRef): SocketHandle

socketOwner ActorRef that should receive events associated with the SocketChannel. The ActorRef for the current Actor will be used implicitly.

If nothing is passed to the curried parameter (only calling server.accept()), the current Actor (Server) will receive events from the SocketChannel. However as the method signature suggests, you can pass an ActorRef to the curried parameter so that events occurring on the SocketChannel will be handled by this new Actor.

Leaving us to the solution added by the owner of the question :

def receive = {
  case IO.NewClient(server) =>
      val client = context.actorOf(Props(new Client()))
      server.accept()(client) // Transferring ownership of the socket to a new Actor
      println("Client accepted")

  case IO.Read(socket, bytes) =>
      println("Server " + bytes)
}