2010-01-14 18 views
6

मुझे ऐसे अभिनेताओं के साथ कुछ परेशानी है जिनमें लंबे समय तक चलने वाले ऑपरेशन होते हैं, मेरे मामले में लगातार सॉकेट कनेक्शन। यहां कुछ परीक्षण कोड दिए गए हैं जो ठीक से चलते हैं यदि मैं चार से कम सर्वर उदाहरण बनाते हैं, लेकिन यदि मैं अधिक उदाहरण बनाता हूं, तो मैं हमेशा केवल तीन या कभी-कभी चार समवर्ती सॉकेट कनेक्शन के साथ समाप्त होता हूं, क्योंकि अन्य समय समाप्त हो जाते हैं। मुझे आश्चर्य है कि यह क्यों है और क्या मेरे कोड के साथ कुछ गलत है।स्कैला अभिनेता: लंबे समय तक चलने वाले आईओ ऑपरेशंस

package test 

import actors.Actor 
import actors.Actor._ 
import java.io.{PrintStream, DataOutputStream, DataInputStream} 
import java.net.{Socket, InetAddress} 
import java.text.{SimpleDateFormat} 
import java.util.{Calendar} 

case class SInput(input: String) 
case class SOutput(output: String) 
case class SClose 
case class SRepeat 

import scala.xml._ 

class Config(xml: Node) { 
    var nick: String = (xml \ "nick").text 
    var realName: String = (xml \ "realName").text 
    var server: String = (xml \ "ip").text 
    var port: Int = (xml \ "port").text.toInt 
    var identPass: String = (xml \ "identPass").text 
    var joinChannels: List[String] = List.fromString((xml \ "join").text.trim, ' ') 
} 

object ServerStarter { 
    def main(args: Array[String]): Unit = { 
    var servers = List[Server]() 

    val a = actor { 
     loop { 
     receive { 
      case config: Config => 
      actor { 
       val server = new Server(config) 
       servers = server :: servers 
       server.start 
      } 
     } 
     } 
    } 

    val xml = XML.loadFile("config.xml") 
    (xml \ "server").elements.foreach(config => a ! new Config(config)) 
    } 
} 


class Server(config: Config) extends Actor { 
    private var auth = false 
    private val socket = new Socket(InetAddress.getByName(config.server), config.port) 
    private val out = new PrintStream(new DataOutputStream(socket.getOutputStream())) 
    private val in = new DataInputStream(socket.getInputStream()) 

    def act = { 
    val _self = this 
    _self ! SRepeat 

    while (true) { 
     receive { 
     case SRepeat => 
      try { 
      val input = in.readLine 
      if (input != null) { 
       actor {_self ! SInput(input)} 
      } else { 
       actor {_self ! SClose} 
      } 
      } catch { 
      case e: Exception => 
       println(e) 
       actor {_self ! SClose} 
      } 

     case SClose => 
      println(getDate + " closing: " + config.server + " mail: " + mailboxSize) 
      try { 
      socket.close 
      in.close 
      out.close 
      } catch { 
      case e: Exception => 
       println(e) 
      } 

     case SInput(input: String) => 
      println(getDate + " " + config.server + " IN => " + input + " mail: " + mailboxSize) 
      actor {onServerInput(_self, input)} 
      _self ! SRepeat 

     case SOutput(output: String) => 
      println(getDate + " " + config.server + " OUT => " + output + " mail: " + mailboxSize) 
      actor { 
      out.println(output) 
      out.flush() 
      } 

     case x => 
      println("unmatched: " + x + " mail: " + mailboxSize) 
     } 
    } 
    } 

    private def getDate = { 
    new SimpleDateFormat("hh:mm:ss").format(Calendar.getInstance().getTime()); 
    } 

    def onServerInput(a: Actor, input: String) = { 
    if (!auth) { 
     authenticate(a) 
    } 
    else if (input.contains("MOTD")) { 
     identify(a) 
     join(a) 
    } 
    else if (input.contains("PING")) { 
     pong(a, input) 
    } else { 
    } 
    } 

    def authenticate(a: Actor) = { 
    a ! SOutput("NICK " + config.nick) 
    a ! SOutput("USER " + config.nick + " 0 0 : " + config.realName) 
    auth = true 
    } 

    def pong(a: Actor, input: String) = { 
    a ! SOutput("PONG " + input.split(":").last) 
    } 

    def identify(a: Actor) = { 
    if (config.identPass != "") { 
     a ! SOutput("nickserv :identify " + config.nick + " " + config.identPass) 
    } 
    } 

    def join(a: Actor) = { 
    config.joinChannels.foreach(channel => a ! SOutput("JOIN " + channel)) 
    } 
} 

बीटीडब्ल्यू। मैं स्कैला 2.7.6 फ़ाइनल का उपयोग कर रहा हूं।

+0

हे मैक्स, लंबे समय तक नहीं देखा! यह देखने के लिए अच्छा है कि आप स्केल को आज़मा रहे हैं। –

उत्तर

6

यहां अजीब चीजें हैं।

actor { 
    val server = new Server(config) 
    servers = server :: servers 
    server.start 
} 

या भी: उदाहरण के लिए:

actor {_self ! SClose} 

विधि actor एक अभिनेता के कारखाने है। पहले मामले में, उदाहरण के लिए, आप एक अभिनेता बना रहे हैं जो एक और अभिनेता बनायेगा (क्योंकि सर्वर एक अभिनेता है), और इसे शुरू करें।

मुझे दोहराने दो: actor { और } के बीच सबकुछ एक अभिनेता है। उस अभिनेता के अंदर, आप new Server कर रहे हैं, जो अन्य अभिनेता बनाता है। और वह receive के अंदर है, जो निश्चित रूप से एक अभिनेता का हिस्सा है। तो, एक अभिनेता के अंदर, आप एक अभिनेता बना रहे हैं जो एक अभिनेता बनायेगा।

और दूसरे उदाहरण पर, आप खुद को एक संदेश भेजने के लिए एक अभिनेता बना रहे हैं। इससे मुझे कोई समझ नहीं आता है, लेकिन मैं अभिनेताओं के साथ अनुभव नहीं कर रहा हूं।

+0

अच्छी तरह से मुझे उन संदेशों को लपेटने का विचार मिला जो मैं यहां से एक अभिनेता के भीतर अभिनेताओं को भेजने का इरादा रखता हूं: http://stackoverflow.com/questions/1549251/scala-actors-worst-practices (दूसरा उत्तर, दूसरा बिंदु) – maxmc

+0

अगर मैं उल्लिखित अभिनेता को हटा दें {} समस्या बनी हुई है। 2 से अधिक समवर्ती सर्वर उदाहरण भरोसेमंद काम नहीं करते हैं। – maxmc

+2

यदि आप अभिनेता के अंदर _not_ हैं तो 'Actor.actor' का उपयोग करना चाहिए। जिन स्थितियों का मैं उल्लेख करता हूं वे अभिनेताओं के अंदर होते हैं। –

संबंधित मुद्दे