1

I am trying to make a scan wether the pc is online or offline. But my current code is way to slow to scan with a good performance as if an computer is offline there is a delay of 3 to 5 seconds. I even added the timeout parameter set as 500 but it still takes more than 3 seconds if a computer is offline.

public bool PingComputer(string computername)
    {
        bool check = false;
        Ping ping = new Ping();
        try
        {
            PingReply reply = ping.Send(computername, 500);
            check = reply.Status == IPStatus.Success;
        }
        catch (PingException)
        {

        }
        return check;
    }

I also already read about asynchron pings but i could´nt find a suitable solution yet that simply returns true if computer is online or false if it is offline.

Thanks in advance.

PoKenius
  • 11
  • 5
  • Is your code too slow because you are checking one computer at a time? Why not do a parallel foreach if not? If that's still not the case make your own ping class that doesn't try reattempts and return false on a short tcp connect timeout. – Sam Marion Apr 11 '18 at 20:30
  • 1
    look at this: https://stackoverflow.com/questions/49069381/why-ping-timeout-is-not-working-correctly?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – Ji Ra Apr 11 '18 at 21:02
  • how many computers are you pinging – TheGeneral Apr 11 '18 at 22:36
  • Computer name needs DNS to be revolved to IP address. You should cache the DNS result if you do want to speed it up. Learn DNS and ICMP protocols if you didn’t yet. – Lex Li Apr 11 '18 at 23:12
  • You need a better definition for "online". Ping may work for one IP address but not another depending on firewall settings. It may work for a system name but not its address depending on the DNS servers. It may not work at all while HTTP does work, again depending on firewall settings. I suggest checking for something more specific like access to a specific site – Ray Fischer Apr 11 '18 at 23:21
  • Is command line ping any faster for *the same computername* when C# Ping is slow? I suspect your problem has absolutely nothing to do with C# Ping, and everything with IP/ICMP ping. – Remus Rusanu Apr 12 '18 at 05:39

1 Answers1

1

If you pretended to Ping a list of Computers you can use Parallel or use async Task.

I tested both methods bellow with the same 77 IPs. Used variable sec = 3.

  • Tasks toke 00:00:02.7146249
  • Parallel toke 00:00:05.9941404

To use the methods

Dictionary<string, bool> pingsReturn = await Network.PingListAsync(dictionary,3);

I can give you the 2 examples:

Task

public static async Task<Dictionary<string, bool>> PingListAsync(Dictionary<string, bool> HostList, int sec = 3)
        {

            // Create a buffer of 32 bytes of data to be transmitted.
            string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
            byte[] buffer = Encoding.ASCII.GetBytes(data);
            // set a quick TTL
            PingOptions options = new PingOptions(20, true);

            // internal support Task to handle Ping Exceptions like "host not found"
            async Task<KeyValuePair<string, bool>> PingHost(string host)
            {
                try
                {
                    var pingresult = await Task.Run(() => new Ping().SendPingAsync(host, sec * 1000, buffer, options));
                    //t.Wait();
                    if (pingresult.Status == IPStatus.Success)
                        return new KeyValuePair<string, bool>(host, true);
                    else
                        return new KeyValuePair<string, bool>(host, false);

                }
                catch
                {
                    return new KeyValuePair<string, bool>(host, false);
                }

            }

            //Using Tasks >>
            var watch = new Stopwatch();
            watch.Start();
            var tasksb = HostList.Select(HostName => PingHost(HostName.Key.ToString()));

            var pinglist = await Task.WhenAll(tasksb);


            foreach (var pingreply in pinglist)
            {
                HostList[pingreply.Key] = pingreply.Value;
            }

            watch.Stop();
            Log.Debug("PingList (Tasks) Time elapsed: " + watch.Elapsed);
            //Using Tasks <<



            return HostList;

        }

Parallel

public static async Task<Dictionary<string, bool>> PingListAsync(Dictionary<string, bool> HostList, int sec = 3)
        {

            // Create a buffer of 32 bytes of data to be transmitted.
            string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
            byte[] buffer = Encoding.ASCII.GetBytes(data);
            // set a quick TTL
            PingOptions options = new PingOptions(20, true);

            //Using Parallel >>
            watch = new Stopwatch();
            watch.Start();

            // avoid exception "Collection was modified; enumeration operation may not execute."
            // we need new dictionary and add values
            Dictionary<string, bool> dictionary = new Dictionary<string, bool>();
            Parallel.ForEach(HostList.Keys, (currHost) =>
            {

                try
                {
                    var pingReply = new Ping().Send(currHost, sec * 1000, buffer, options);
                    if (pingReply.Status == IPStatus.Success)
                        dictionary.Add(currHost, true);
                    else
                        dictionary.Add(currHost, false);
                }
                catch
                {
                    // handle Ping Exceptions like "host not found"
                    dictionary.Add(currHost, false);
                }


            });
            watch.Stop();
            Log.Debug("PingList (Parallel) Time elapsed: " + watch.Elapsed);
            //Using Parallel <<

            return dictionary;

        }

PS - I know this is an old question, but is still valid.

Rui Caramalho
  • 455
  • 8
  • 16