views:

407

answers:

4

Given a range of IP addresses entered by a user (through various means), I want to identify which of these machines have software running that I can talk to.

Here's the basic process:

  1. Ping these addresses to find available machines

  2. Connect to a known socket on the available machines

  3. Send a message to the successfully established sockets

  4. Compare the response to the expected response

Steps 2-4 are straight forward for me. What is the best way to implement the first step in .NET?

I'm looking at the System.Net.NetworkInformation.Ping class. Should I ping multiple addresses simultaneously to speed up the process? If I ping one address at a time with a long timeout it could take forever. But with a small timeout, I may miss some machines that are available.

Sometimes pings appear to be failing even when I know that the address points to an active machine. Do I need to ping twice in the event of the request getting discarded?

To top it all off, when I scan large collections of addresses with the network cable unplugged, Ping throws a NullReferenceException in FreeUnmanagedResources(). !?

Any pointers on the best approach to scanning a range of IPs like this?

+4  A: 

Don't forget the headache of the people who will deny pinging in their firewall rules.

My only suggestion is perhaps a question: Do you have to do #1?

Can't you simply try to connect to that known socket? Successful connection to that socket kills two birds with one stone: yes the host is there/alive, and yes, the known-socket is open.

This type of situation does lend itself well to multithreading, fire it off on another thread, and wait for it to come back with an answer...

Yoopergeek
The only issue with this approach would be time. If the address range is 256+ addresses, is it feasible to try to open a socket to each one? How long would the timeout have to be? Could I try to open several sockets at once?
Josh G
You could for example make 4 async sockets and start trying to connect to the machines, that way you can try 4 connections at a time. Add as many sockets as you want!
DaMacc
The only problem is that ping is unreliable because of firewalls and such. The only alternative is to skip it entirely. I'd probably go with something like @DaMacc is suggesting - simply thread-off N-threads at a time...
Yoopergeek
Any limits on the highest number of sockets that I could realistically use at a time before something choked?
Josh G
I am not aware of any limit, but then I'm not well-versed in socket programming, so I can't be sure. Without an exact answer, I'd play it conservatively... 5-to-10 connections, maybe? That's where I'd start.
Yoopergeek
I don't think this is going to work. I can't find a way to force the Socket.Connect(IPAddress, int) function to time out if the host is unreachable. I can't wait 10-20 seconds for each connection to time out. Sometimes 60-80% of the connections will time out! Is there a way to set the connection timeout on a socket?
Josh G
I repeat my previous comment: "I'm not well-versed in socket programming..." So sorry, no, I'm not aware of how you could go about that. Time for another question, perhaps?
Yoopergeek
+2  A: 

Since not all machines respond to pings (depending on firewall settings) I suggest skipping step 1 if possible.

If you know the machines you will be connecting to respond to pings the ping class works well enough. It only sends 1 packet so ping more than once in case it gets dropped. Also, in my experience the ping class will often throw an exception instead of returning a PingReply object if the host is unreachable.

This is my suggested implementation:

public bool
   Ping (string host, int attempts, int timeout)
   {
      System.Net.NetworkInformation.Ping  ping = 
                                       new System.Net.NetworkInformation.Ping ();

      System.Net.NetworkInformation.PingReply  pingReply;

      for (int i = 0; i < attempts; i++)
      {
         try
         {
            pingReply = ping.Send (host, timeout); 

            // If there is a successful ping then return true.
            if (pingReply != null &&
                pingReply.Status == System.Net.NetworkInformation.IPStatus.Success)
               return true;
         }
         catch
         {
            // Do nothing and let it try again until the attempts are exausted.
            // Exceptions are thrown for normal ping failurs like address lookup
            // failed.  For this reason we are supressing errors.
         }
      }

      // Return false if we can't successfully ping the server after several attempts.
      return false;
   }
Eric
A: 

Sounds suspiciously like someone trying to write a botnet and scanning subnets for infected PCs.

There's hardly ever a reason to "detect computers on the network", let them talk to you instead when and if they want to.

jwenting
Actually it's a configuration tool for hardware devices. I'm trying to identify where the devices are at. Having the devices talk to me would not change the problem. They would be randomly pinging to find the configuration PC just like the configuration PC is doing now.
Josh G
A: 

As many people mentioned Ping is not the best ways to detect if the machine is alive, if it is an absolute must to detect all available machine on the subnet, you could use some of the trick nmap scanner uses, to detect available machines.

Vitalij