16

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 ?

sia
  • 1,872
  • 1
  • 23
  • 54
  • 3
    What does exactly `Ping.getIPAddress()`? It seems to be sync, but you may be able to do a various background calls simultaniously. – Larme Sep 02 '15 at 15:35
  • 1
    @Larme - this fucntion will look for a given IP address. If it exists it will return true and if not then it will return false. – sia Sep 02 '15 at 15:37
  • 3
    Your `for loop` should start from `0`, not `1`. – Luca Angeletti Sep 04 '15 at 18:45
  • 1
    Firstly the address you are using is illegal. 289 is not a valid IP entry. Must be less than 255. Is this router is the main router for your connection? If so then it is probably the default gateway for your device, so just look that up? Also if you are part of that network, you can just send a single ping to the network broadcast address and wait to see who replies. – Rory McKinnel Sep 07 '15 at 10:16
  • @appzYourLife Starting at 0 would not be correct for an IP address as they start at .1. It should stop at 254 though as 255 will be the network broadcast address 8^). – Rory McKinnel Sep 07 '15 at 10:20
  • @RoryMcKinnel You cannot say if an address ending by .0 or .255 is valid or not, unless you have the netmask. – BPCorp Sep 08 '15 at 12:23
  • @BPCorp Yes. However as the full range was noted to be .0 to .255, the assumption I made was that his network is 163.(289?).2.0/24, which would make .0 the network address and .255 the broadcast address. Thus the loop should miss out 0 and 255. If its not /24, then you would be correct. – Rory McKinnel Sep 08 '15 at 13:35

1 Answers1

14

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.

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148