Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Akka Socket per actor

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!

like image 923
tkblackbelt Avatar asked Jan 18 '13 21:01

tkblackbelt


1 Answers

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)
}
like image 86
abronan Avatar answered Oct 12 '22 09:10

abronan