【问题标题】:Background Worker Ping后台工作人员 Ping
【发布时间】:2023-11-20 14:14:01
【问题描述】:
  • 问题:Ping 离线设备需要 10-15 秒。

  • 目标:如果 ping 或后台工作程序运行时间超过 5 秒,我想结束/杀死/停止或任何必要的后台工作程序。 有什么建议我该怎么做?

目前,当我 ping 一台在线设备时,它会在第一秒内回复。

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";
        }
    }            
}

【问题讨论】:

    标签: c# .net backgroundworker ping


    【解决方案1】:

    再次编辑:

    正如我之前的“编辑”中所述,您已经在代码中设置了 ping 超时。所以你真的不应该有 5...15 秒的延迟操作。也许问题出在其他地方?

    例如,使用以下代码(简单的控制台应用程序),它迭代 IP 列表,然后显示每个 IP 的 ping 结果,格式为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);
                    });
            }
        }
    }
    

    或多或少地输出以下内容。

    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
    

    没有一个请求花费超过一 (1) 秒,这是我自己设置的超时时间。

    所以答案是: 将每个请求作为新任务启动并完全放弃后台工作程序,将 ping 超时设置为您实际需要的级别,并在需要时使用 .BeginInvoke() 将响应委托回 UI 线程(而不是 Invoke())。

    希望这对您有所帮助!

    编辑:

    好的,我看到您已经将timeout 设置为 100 毫秒,所以应该不会花很长时间。但随后您执行以下操作:

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

    它会帮助你摆脱那里的循环吗?


    也许您可以将所有 ping 作为单独的任务启动,并让它们根据需要一直存在?

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

    【讨论】:

    • 我不熟悉这种方法。你如何建议我在 x 秒后杀死线程?
    • 一般来说,你不应该杀死/强制线程结束。我认为您让线程自行退出没有什么害处?
    • 让他们自行退出需要 10-15 秒才能结束。我想让我的主线程(表单)更快地更新我的用户。我需要在 10-15 秒内更快地向我的用户提供“离线”信息。你明白我在问什么吗?
    • 感谢您的澄清。所以假设状态是离线就足够了(因为在你得到答案之前就是这样)?我需要考虑清楚。
    • 没错!如果花费的时间超过几秒钟,则可以安全地假定它处于脱机状态。很抱歉第一次不清楚。
    【解决方案2】:
    using System.Net.NetworkInformation;
    
    Ping pingSender = new Ping ();
            PingOptions options = new PingOptions ();
            options.DontFragment = true;
            string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
            byte[] buffer = Encoding.ASCII.GetBytes (data);
            int timeout = 1000; //to timeout after 1s
            PingReply reply = pingSender.Send (args[0], timeout, buffer, options);
            if (reply.Status == IPStatus.Success)
            {
                Console.WriteLine ("Address: {0}", reply.Address.ToString ());
                Console.WriteLine ("RoundTrip time: {0}", reply.RoundtripTime);
                Console.WriteLine ("Time to live: {0}", reply.Options.Ttl);
                Console.WriteLine ("Don't fragment: {0}", reply.Options.DontFragment);
                Console.WriteLine ("Buffer size: {0}", reply.Buffer.Length);
            }
    

    http://msdn.microsoft.com/en-us/library/system.net.networkinformation.ping(v=vs.110).aspx中的更多示例

    【讨论】:

    • 问题不是如何使用 Ping,而是如何杀死它。
    • 是的。如果您使用 NetworkInformation.Ping 和 timeout 参数,您不必尝试手动杀死它。在我看来,这是 OPs 问题的有效解决方案。