Search code examples
c#.netbackgroundworkerping

Background Worker Ping


  • Problem: When Pinging an offline device it takes 10-15 seconds.

  • Goal: I would like to end/kill/stop or what ever is necessary the background worker if the ping or backgroundworker runs for longer then 5 seconds. Any suggestions how i can do this?

Currently when i ping a device that's online it reply back within the first second.

private void backgroundWorkerPing_DoWork(object sender, DoWorkEventArgs e)
{
    string pcName = e.Argument.ToString();

    lblIPAddress.Invoke((Action)(() => lblIPAddress.ForeColor = Color.Black));

    lblStatus.GetCurrentParent().Invoke((Action)(() => lblStatus.Text = String.Format("Pinging {0}", pcName)));                

    string ipAddress = GetSinglePing(pcName);                       
    e.Result = ipAddress;
}

private string GetSinglePing(string pcName)
{
    Network net = new Network();
    return net.Pinger(pcName);
}

public class Network
{
    //My Ping Method
    public string Pinger(string pcName, int bufferSize = 32)
    {
        Ping ping = new Ping();
        byte[] buffer = new byte[bufferSize];
        PingOptions pingOpt = new PingOptions(64, true);            

        try
        {
            PingReply pingReply = ping.Send(pcName, 100, buffer, pingOpt);

            if (pingReply.Status == IPStatus.Success)
            {
                return pingReply.Address.ToString();
            }
            else
            {
                return "Offline";
            }
        }
        catch
        {
            return "Offline";
        }
    }            
}

Solution

  • Edit again:

    As stated in my previous "edit", you already have ping timeout set in your code. So you really should not have 5...15 second delays for your operation. Maybe problem is somewhere else?

    For example, take the following code (simple console app), which iterates list of IPs and then displays ping results for each, in format of IP - STATE - TIME USED

    public class Program
    {
        private static void Main(string[] args)
        {
            var p = new Program();
            p.PingPong();
            Console.ReadLine();
        }
    
        private void PingPong()
        {
             var ips = new List<string>()
                {
                    "43.128.240.28",
                    "159.203.123.166",
                    ... 30 in total in this test ...
                    "201.131.43.87",
                    "108.232.183.145"
                };
    
            foreach (var ip in ips)
            {
                string ip1 = ip;
                Task.Factory.StartNew(async () =>
                    {
                        var newtwork = new Network();
                        var start = DateTime.Now;
                        string ping = newtwork.Pinger(ip1);
                        Console.WriteLine("{0} - {1} - {2}ms", ip, ping, (DateTime.Now - start).TotalMilliseconds);
                    });
            }
        }
    }
    

    Outputs more or less the following.

    75.146.125.27 - Offline - 998.0982ms
    190.37.198.208 - Offline - 978.329ms
    90.82.250.179 - Offline - 975.3303ms
    141.231.190.96 - Offline - 998.3851ms
    38.89.231.171 - Offline - 976.3265ms
    183.179.51.148 - Offline - 999.1762ms
    125.238.115.199 - Offline - 977.1139ms
    201.131.43.87 - Offline - 975.1229ms
    154.165.188.89 - Offline - 978.1232ms
    86.8.40.161 - Offline - 979.1236ms
    108.232.183.145 - Offline - 998.6617ms
    

    None of the requests took more than one (1) second, which was the timeout I set myself.

    So answer is: Launch each request as new task and ditch the backgroundworker alltogether, setting ping timeout to the level you actually need, and delegate response back to UI thread using .BeginInvoke() if needed (not Invoke()).

    Hope this helps you forward!

    Edit:

    Ok, so I see you already set the timeout to 100ms so it shouldn't take long. But then you do the following:

    PingReply pingReply;
    do
    {
        pingReply = ping.Send(pcName, 100, buffer, pingOpt);                    
    }
    while(pingReply.Status != IPStatus.Success);
    return pingReply.Address.ToString();    
    

    Would it help you just get rid of the loop there?


    Maybe you could launch all your pings as separate tasks and just let them live as long as needed?

    Task.Factory.StartNew(() => Pinger("pcName"));