2010-12-02 22 views
2

Dans Scala, il est très facile de se connecter à un acteur distant, mais la documentation ne me dit rien sur la déconnexion. Le simple fait de jeter la référence ne fonctionne pas, car les acteurs distants sont des acteurs, donc ceux-ci ne seront pas collectés avant d'être stoppés. Alors, comment me déconnecter?Comment déconnecter un Scala Remote Actor?

Cela ne Terminate après la sortie:

import actors.{DaemonActor,remote} 
import remote.{RemoteActor,Node} 

object SimpleClient{ 
    val messageHandler = new DaemonActor{ 
     def act{ 
      loop{ 
       react{ 
        case message:String => 
         println("got message: " + message) 
        case _ => 
       } 
      } 
     } 
     start 
    } 

    def main(args:Array[String]){ 
     val server = RemoteActor.select(Node("localhost",9999),'server) 
     server.send('Connect,messageHandler) 

     var exit = false 
     while(!exit){ 
      val message = Console.readLine 
      if(message == "exit" || message == "quit") { 
       exit = true 
       server ! 'Disconnect 
      } 
      else 
       server ! message 
     } 
    } 
} 

Ce serveur:

import actors.{Actor,OutputChannel} 
import actors.remote.RemoteActor 

object Server extends Actor{ 
    val clients = new collection.mutable.HashSet[OutputChannel[Any]] 
    def act{ 
     loop{ 
      react{ 
       case 'Connect => 
        clients += sender 
       case 'Disconnect => 
        clients -= sender 
       case message:String => 
        for(client <- clients) 
         client ! message 
      } 
     } 
    } 

    def main(args:Array[String]){ 
     start 
     RemoteActor.alive(9999) 
     RemoteActor.register('server,this) 
    } 
} 

Répondre

1

Voici une version de travail de la source, avec des changements pertinents commenté en ligne:

import actors.{DaemonActor,remote} 
import remote.{RemoteActor,Node} 

case class Send(message: String) 
case object Disconnect 

object SimpleClient{ 
    val messageHandler = new DaemonActor{ 

     def act{ 
      // keep the reference to the proxy inside the client-side actor 
      val server = RemoteActor.select(Node("localhost",9999),'server) 
      server ! 'Connect 
      loop{ 
      react{ 
       case message:String => 
        println("got message: " + message) 
       case Send(message) => server ! message 
       case Disconnect => { 
        // disconnect and exit the client-side actor 
        server ! 'Disconnect //' 
        exit 
       } 
       case _ => 
       } 
      } 
     } 
     start 
    } 

    def main(args:Array[String]){ 
     var exit = false 
     while(!exit){ 
     val message = Console.readLine 
     if(message == "exit" || message == "quit") { 
      exit = true 
      // tell the client-side actor to exit 
      messageHandler ! Disconnect 
     } else { 
      messageHandler ! Send(message) 
     } 
     } 
    } 
} 
+0

cool qui fonctionne, merci. J'ai vu que vous aviez déplacé le serveur à l'intérieur du gestionnaire de messages, mais pourquoi cela se comporte-t-il différemment de l'enregistrement du serveur dans le bloc de la boucle principale? – Arne

2

Votre question est vraiment pas assez clair sur ce problème que vous pensez que vous rencontrez. Acteurs font pas "se connecter" les uns aux autres (comme une socket). Vous envoyez un message à un acteur parce que vous avez une référence à celui-ci (ou un proxy, dans le cas des acteurs distants).

Avoir une telle référence n'empêche pas l'acteur (l'un ou l'autre acteur) de s'arrêter. S'il n'y a plus de références à un acteur et qu'il n'est pas en cours d'exécution, rien ne l'empêche d'être récupéré par les ordures

+0

Cest le point. L'acteur distant est toujours en cours d'exécution. Les acteurs sur le serveur doivent continuer à fonctionner, c'est le travail du serveur, tout comme les acteurs distants du côté client. Ces proxies empêchent mon programme de s'arrêter correctement. – Arne

+0

@Arne - J'ai bien peur que ce ne soit pas assez clair. Pourquoi ne peux-tu pas juste «sortir» des acteurs que tu veux arrêter? –

+0

Il y a un acteur sur le serveur qui reçoit les connexions des clients. Vous pouvez l'appeler l'acteur de bienvenue. Cet acteur ne doit pas s'arrêter, car c'est le même acteur pour tous les clients. Je ne peux pas le tuer seulement parce qu'un client veut éteindre sa JVM. Je veux seulement tuer l'instance distante de cet acteur – Arne

2

Le trait Reactor définit protected[actors] def exit(): Nothing que l'acteur peut appeler lui-même à la réception d'un message lui indiquant de faire alors.

sealed trait Msg 
case object Apoptosis extends Msg 
// ... more messages 


class RRActor extends Reactor[Msg] { 
    def act = loop { 
    react { 
     // ... Whatever messages the actor handles 
     case Apoptosis => this.exit 
    } 
    } 
} 

Edit: Je n'ai jamais testé cela avec des acteurs distants.

+0

Il ne faut * pas * dire à 'exit'! Il peut décider lui-même de 'exit' quand il le veut –

+0

Est-ce qu'il sortira si vous utilisez loop? Comment et pourquoi décide-t-il de sortir? Mon utilisation des acteurs a été limitée et cette astuce est ce que j'utilise. – fedesilva

3

[Disclaimer: Je suis PO d'Akka]

je suggère de jeter un oeil à Akka, qui a été construit avec les acteurs à distance à l'esprit du jour 1? www.akka.io

+0

Ne pas oublier la divulgation (http://stackoverflow.com/faq#promotion) :) –

+0

Merci pour cela Aaron, j'essaie d'être clair sur mes affiliations :-) –