2

このコードでは、メインアクターのactメソッドのケースが一致することはないため、wrapUpメソッドが呼び出されることはありません。

import java.net.Socket
import scala.actors._
import Actor._
import scala.collection.mutable.ArrayBuffer

object LowPortScanner {

  var lastPort = 0
  var openPorts = ArrayBuffer[Int]()
  var longestRunTime = 00.00
  var results = List[Tuple3[Int, Range, Long]]()

  val host = "localhost"
  val numProcs = 1 to Runtime.getRuntime().availableProcessors()
  val portsPerProc = 1024 / numProcs.size
  val caller = self
  val procPortRanges = numProcs.foldLeft(List[Tuple2[Int, Range]]()) { (portRanges, proc) =>
    val tuple2 = (proc.toInt, (lastPort + 1) to (lastPort + portsPerProc))
    lastPort += portsPerProc
    tuple2 :: portRanges
  }

  def main(args: Array[String]): Unit = {

    //spawn an actor for each processor that scans a given port range
    procPortRanges.foreach { proc =>
      actor {
        caller ! scan(proc._1, proc._2)
      } //end inner actors
    } //end numProcs.foreach  

    //catch results from the processor actors above
    def act {
      loop {
        reactWithin(100) {
          //update the list of results returned from scan
          case scanResult: Tuple3[Int, Range, Long] =>
            println("Processor " + scanResult._1 + " completed scan of ports " + scanResult._2.first + " through " + scanResult._2.last)
            results = results ::: List(scanResult)

          //check if results have been returned for each actor
          case TIMEOUT =>
            println("Main actor timed out")
            if (results.size == numProcs.size) wrapUp

          case _ =>
            println("got back something weird from one of the port scan actors!")
            wrapUp
        }
      }
    }    

    //Attempt to open a socket on each port in the given range
    //returns a Tuple3[procID: Int, ports: Range, time: Long
    def scan(proc: Int, ports: Range) = {
      val startTime = System.nanoTime()
      ports.foreach { n =>
        try {
          //println("Processor " + proc + " is checking port " + n)
          print(".")

          val socket = new Socket(host, n)

          //println("Found open port: " + n)
          openPorts += n

          socket.close
        } catch {
          case e: Exception =>
          //println("While scanning port " + n + " caught Exception: " + e)
        }
      }
      (proc, ports, startTime - System.nanoTime())
    }

    //output results and kill the main actor
    def wrapUp {
      println("These are the open ports in the range 1-1024:")
      openPorts.foreach { port => println(port) }
      results.foreach { result => if (result._3 > longestRunTime) { longestRunTime = result._3 } }
      println("Time to scan ports 1 through 1024 is: %3.3f".format(longestRunTime / 1000))
      caller ! exit
    }
  }
}

各プロセッサのアクターを生成するコードは正常に機能し、スキャンメソッドはポートの範囲ごとに正しく呼び出され、正確に1024個のポートがスキャンされることを確認しました。
私の期待は、次の行です。

caller ! scan(proc._1, proc._2)  

(Int、Range、Long)を含むメッセージをメインアクターに送り返す必要があります。次に、メインアクターのactメソッドは、そのメッセージをキャッチして実行する必要があります。

          case scanResult: Tuple3[Int, Range, Long] =>
            println("Processor " + scanResult._1 + " completed scan of ports " + scanResult._2.first + " through " + scanResult._2.last)
            results = results ::: List(scanResult)  

ただし、これは発生していません。実際、私が知る限り、私のメッセージはどれもメインアクターに返されていません。何が欠けているのか、何が間違っているのかはっきりしていません。

4

1 に答える 1

2

お気づきのように、送信されているメッセージが受信されていないという問題があります。これは、で作成されたアクターに定義が関連付けられてactor {caller ! scan(proc._1, proc._2)}いないためです。actこのdef act{...}メソッドは、アクターではなくオンのメソッドであるため、作成されたアクターとは何の関係もLowPortScannerありません。

コードの精神を維持しながら、内のアクターによって実行される本体を定義し、 actor{...}それを値に割り当ててメッセージを送信できます。

 //spawn an actor for each processor that scans a given port range
 procPortRanges.foreach { proc =>
   val myactor = actor {
     //catch results from the processor actors above
       loop {
         reactWithin(100) {
         //update the list of results returned from scan
         case scanResult: Tuple3[Int, Range, Long] =>
           println("Processor " + scanResult._1 + " completed scan of ports " + scanResult._2.first + " through " + scanResult._2.last)
           results = results ::: List(scanResult)

         //check if results have been returned for each actor
         case TIMEOUT =>
           println("Main actor timed out")
           if (results.size == numProcs.size) wrapUp

         case _ =>
           println("got back something weird from one of the port scan actors!")
           wrapUp
        }
      }
     //catch results from the processor actors above
   } //end inner actors
     myactor ! scan(proc._1, proc._2)
 } //end numProcs.foreach

これを行う別の方法は、アクターの特性を拡張することです。このようにして、はアクターdef act{...}が受信したメッセージを処理します。また、の代わりにLowPortScannerを使用するなど、いくつかのマイナーなリファクタリングを行いました。アクターもで開始する必要がありました。thisselfthis.start()

import java.net.Socket
import scala.actors._
import Actor._
import scala.collection.mutable.ArrayBuffer

object LowPortScanner extends Actor {

  var lastPort = 0
  var openPorts = ArrayBuffer[Int]()
  var longestRunTime = 00.00
  var results = List[Tuple3[Int, Range, Long]]()

  val host = "localhost"
  val numProcs = 1 to Runtime.getRuntime().availableProcessors()
  val portsPerProc = 1024 / numProcs.size

  val procPortRanges = numProcs.foldLeft(List[Tuple2[Int, Range]]()) { (portRanges, proc) =>
    val tuple2 = (proc.toInt, (lastPort + 1) to (lastPort + portsPerProc))
    lastPort += portsPerProc
    tuple2 :: portRanges
  }
    //catch results from the processor actors above
    def act {
      loop {
        reactWithin(100) {
          //update the list of results returned from scan
          case scanResult: Tuple3[Int, Range, Long] =>
            println("Processor " + scanResult._1 + " completed scan of ports " + scanResult._2.first + " through " + scanResult._2.last)
            results = results ::: List(scanResult)

          //check if results have been returned for each actor
          case TIMEOUT =>
            println("Main actor timed out")
            if (results.size == numProcs.size) wrapUp

          case _ =>
            println("got back something weird from one of the port scan actors!")
            wrapUp
        }
      }
    }

    //Attempt to open a socket on each port in the given range
    //returns a Tuple3[procID: Int, ports: Range, time: Long
    def scan(proc: Int, ports: Range) = {
      val startTime = System.nanoTime()
      ports.foreach { n =>
        try {
          //println("Processor " + proc + " is checking port " + n)
          print(".")

          val socket = new Socket(host, n)

          //println("Found open port: " + n)
          openPorts += n

          socket.close
        } catch {
          case e: Exception =>
          //println("While scanning port " + n + " caught Exception: " + e)
        }
      }
      (proc, ports, startTime - System.nanoTime())
    }

    //output results and kill the main actor
    def wrapUp {
      println("These are the open ports in the range 1-1024:")
      openPorts.foreach { port => println(port) }
      results.foreach { result => if (result._3 > longestRunTime) { longestRunTime = result._3 } }
      println("Time to scan ports 1 through 1024 is: %3.3f".format(longestRunTime / 1000))
      this ! exit
    }

  def main(args: Array[String]): Unit = {

    //spawn an actor for each processor that scans a given port range
    this.start()
    procPortRanges.foreach { proc =>
      actor {
        this ! scan(proc._1, proc._2)
      } //end inner actors
    } //end numProcs.foreach  
  }

}

実行の結果は次のとおりです。

scala> LowPortScanner.main(Array[String]())

scala> ...Processor 6 completed scan of ports 641 through 768
...Processor 5 completed scan of ports 513 through 640
...Processor 4 completed scan of ports 385 through 512
...Processor 3 completed scan of ports 257 through 384
...Processor 1 completed scan of ports 1 through 128
...Processor 7 completed scan of ports 769 through 896
...Processor 2 completed scan of ports 129 through 256
...Processor 8 completed scan of ports 897 through 1024
Main actor timed out
These are the open ports in the range 1-1024:
139
22
445
591
631
111
Time to scan ports 1 through 1024 is: 0.000


scala> LowPortScanner.results
res2: List[(Int, Range, Long)] = List((6,Range(641, 642, 643,...
于 2012-11-09T23:06:40.333 に答える