Click here to Skip to main content
15,887,027 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am pinging all devices on a class-c lan .1 - .254 without regard to whether ping replies or not. This works and only takes about 15 seconds.

C#
Parallel.For(0, 254, i =>
            {
                Ping ping = new Ping();
                ping.Send(LocalIpAddress + '.' + (i + 1), 1);
            });


But I think it might be quicker if I don't call the Ping constructor for each iteration. However, I don't have a clue as to how that might be done.

TIA!

What I have tried:

Lots of things that either won't compile or go into the weeds.
Posted
Updated 13-Sep-23 4:30am
v2

It's not the constructor for Ping.

You have to understand how this works on several levels. First, Ping has to send a packet out, possible to an IP that doesn't have a device listening for it. So, it has to wait for a response, or non-response. If there's a response, OK, great. It can be done with the operation and report a result. For a non-response, it has to wait for a timeout before it gives up and reports that failure result. That timeout is, by default, 5 seconds. You can change the timeout, giving it a new value in milliseconds, in the Send method. You can make that timeout smaller, but you have to keep in mind that you have to give the remote device time to receive the ICMP packet and send a response back, which will NOT happen instantly.

Keeping all that in mind, now you have to look at how Parallel works. In simple terms, it looks at the number of cores your CPU has and divides up the workload (number of items) between the number of cores. Each core gets an item to work on (a thread), one at a time. Each one of those threads can be stuck waiting for the timeout mentioned above. So, if your CPU has, say, 6 cores, those threads can all be stuck waiting for an I/O operation to timeout, and on a network with probably over 200 addresses where nothing is listening, all those timeouts can add up to 15 seconds over 6 threads quite easily.

Aaaaand you have to keep in mind that your application does NOT have exclusive use of the CPU. It has to share those 6 (or whatever) cores with the thousands of other threads Windows is running all the time, and that is going to add to the time your application is waiting.

Like I said, you can change the timeout to a lower number, but you have to balance that with the time you need to wait for devices to respond (and even wake up to respond!) and the amount of time you want this scan to run in.
 
Share this answer
 
Comments
Ron Anders 3-Sep-23 13:41pm    
Timeout is set to 1 or 1ms already, which seems to be the smallest possible value supported.
Dave Kreskowiak 3-Sep-23 14:23pm    
Yeah, it is and is not sufficient for the reasons I stated above. Sure, you can get through 254 IP addresses, but you can also get a lot of failures to respond.
For anyone who comes across this thread here is a new way that is faster than a scalded cat. hard coded ip for POC.

C#
private async Task<List<PingReply>> PingAsync()
        {
            List<string> theListOfIPs = new List<string>();
            for (int i = 1; i != 255; i++)
            {
                theListOfIPs.Add("192.168.1." + i);
            }
            var tasks = theListOfIPs.Select(ip => new Ping().SendPingAsync(ip, 2000));
            var results = await Task.WhenAll(tasks);

            return results.ToList();
        }
 
Share this answer
 
v2
Comments
Dave Kreskowiak 3-Sep-23 17:07pm    
How is it faster? The difference between the code you originally posted and the new code is instead of waiting for Parallel to create the tasks itself, you're creating all the tasks at once, which can see like it's much faster. You still have the problem of the task scheduler running the same number of tasks on the same hardware. It can be faster to create the tasks, but not to get the responses. You're still going to run all the pings in 10 to 15 seconds.

If you drop the timeout from 2000 to 1000, you're actually start replacing the Destination Unreachable errors with Timeouts instead. For devices on your local 192.168 network, 1000 milliseconds should be enough for just about any device to response, so the error state isn't going to matter.
Dave Kreskowiak 3-Sep-23 17:49pm    
I see it now. Your call to WhenAll is fooling you. WhenAll creates another task that completes when all of the tasks it is given are complete. The return statement is returning a list of results that may not be complete yet. Change the WhenAll to WaitAll and you'll get the complete list of results.

In other words, the code you've posted does not wait for any of the tasks you created to complete before returning results.
When I change it to WaitAll, the tasks gets a red squidly. It's doing what I needed which was this: I have a gather mac addresses routine that is to detect when a user has attached a new printer to the network where the ip is unknown. I found that while The printer was up and ready it would not show up even in ARP -a. until pinged. This is why I need to ping the network so that the following mac get will get the new printers. While I may be just getting lucky, it's working I can add/remove various printers and they are being detected.
 
Share this answer
 
Comments
Dave Kreskowiak 3-Sep-23 19:17pm    
You posted this as another solution to your own question, not as a response to anything I posted. I don't get an email that says you "replied" when you do this.

The line would be
Task.WaitAll(tasks.ToArray());

It's important to wait for the ping to complete, otherwise you're going to run the ARP command and still not get a response.
Dave Kreskowiak 4-Sep-23 11:47am    
Oh, and 1 is 1 millisecond, not 100.
Ron Anders 4-Sep-23 21:13pm    
Well that all works nicely now and takes about 2 or 3 seconds to scour the whole lan. Thanks for all your guidence on this.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900