J'ai pas mal de problèmes avec les acteurs qui contiennent des opérations de longue durée, dans mon cas, les connexions socket persistantes. Voici un code de test qui fonctionne correctement si je crée moins de quatre instances de serveur, mais si je crée plus d'instances, je finis toujours avec seulement trois ou quatre connexions socket simultanées, car les autres expirent. Je me demande pourquoi et si quelque chose ne va pas dans mon code.scala acteurs: fonctionnement long io opérations
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))
}
}
btw. J'utilise scala 2.7.6 final.
Salut Max, long temps pas vu! Cool pour voir que vous essayez Scala. –