sia
sia

Reputation: 1910

optimized way to search a device ip address within a range in iphone

I have situation where-in i have to search IP address of **router ** and I know only it's range is from range 163.289.2.0 to 163.289.2.255. I know this is not good way to search.

for i in 1... 255 {

var str = "163.289.2." + "i"
var tempIP = Ping.getIPAddress(str)

if(tempIP == true)
{
   break;
}

}

Now my problem is my custom class Ping.getIPAddress() takes 3 seconds to get the result for a given IP value. So for 255 searches it takes approx 765 seconds (12.75 minutes). I have restriction that search should complete in max 2 minutes. So is there anyway i can achieve this in iPhone using swift.

I must use only this custom function Ping.getIPAddress() which gives true if given IP address exists else false.

Please provide me example or reference or approach to solve this issue .

Using NSOperationQueue with MaxConcurrentOperationCount set to 10 will be good ?

Upvotes: 16

Views: 863

Answers (1)

Luca Angeletti
Luca Angeletti

Reputation: 59516

Synchronous approach

If we perform each call to Ping.getIPAddress(str) only after the previous one has completed of course we need to wait for (3 seconds * 256) = 768 seconds.

enter image description here

Asynchronous approach

On the other hand we can perform several concurrent calls to Ping.getIPAddress(str).

enter image description here

The fake Ping class

This is a class I created to test your function.

class Ping {
    class func getIPAddress(str:String) -> Bool {
        sleep(3)
        return str == "163.289.2.255"
    }
}

As you see the class does wait for 3 seconds (to simulate your scenario) and then returns true only if the passed ip is 163.289.2.255. This allows me to replicated the worst case scenario.

Solution

This is the class I prepared

class QuantumComputer {

    func search(completion:(existingIP:String?) -> ()) {
        var resultFound = false
        var numProcessed = 0
        let serialQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL)
        for i in 0...255 {

            dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_UTILITY.value), 0)) {
                var ip = "163.289.2." + "\(i)"
                let foundThisOne = Ping.getIPAddress(ip)

                dispatch_async(serialQueue) {
                    if !resultFound {
                        resultFound = foundThisOne
                        numProcessed++
                        if resultFound {
                            completion(existingIP:ip)
                        } else if numProcessed == 256 {
                            completion(existingIP: nil)
                        }
                    }
                }
            }
        }
    }
}

The class performs 256 asynchronous calls to Ping.getIPAddress(...).

The results from the 256 async closures is processed by this code:

dispatch_async(serialQueue) {
    if !resultFound {
        resultFound = foundThisOne
        numProcessed++
        if resultFound {
             completion(existingIP:ip)
        } else if numProcessed == 256 {
             completion(existingIP: nil)
        }
    }
}

The previous block of code (from line #2 to #9) is executed in my queue serialQueue. Here the 256 distinct closures run synchronously.

  1. this is crucial to ensure a consistent access to the variables resultFound and numProcessed;
  2. on the other hand this is not a problem by a performance point of view since this code is pretty fast (just a bunch of arithmetic operations)

Test

And this is how I call it from a standard ViewController.

class ViewController: UIViewController {
    var computer = QuantumComputer()


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        debugPrintln(NSDate())
        computer.search { (existingIP) -> () in
            debugPrintln("existingIP: \(existingIP)")
            debugPrintln(NSDate())
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

Conclusions

Finally this is the output when I test it on my iOS simulator. Please remind that this is the worst case scenario (since the last checked number is a valid IP).

2015-09-04 20:56:17 +0000
"existingIP: Optional(\"163.289.2.255\")"
2015-09-04 20:56:29 +0000

It's only 12 seconds!

Hope this helps.

Upvotes: 14

Related Questions