首页 > 解决方案 > Ping.SendAsync 陷入无限循环

问题描述

我正在尝试获取本地网络上所有主机的列表。按照这个 Stackoverflow 线程。但是 Ping.SendAsync() 卡在无限循环中,即使我保持很小的超时时间,即 20。这是我的代码。

        static CountdownEvent countdown;
        static int upCount = 0;
        static object lockObj = new object();
        const bool resolveNames = false;
        static List<string> activeInterfaces = new List<string>();

        static void p_PingCompleted(object sender, PingCompletedEventArgs e)
        {
            try
            {

                string ip = (string)e.UserState;
                if (e.Reply != null && e.Reply.Status == IPStatus.Success)
                {
                    //if (resolveNames)
                    //{
                    //    string name;
                    //    try
                    //    {
                    //        IPHostEntry hostEntry = Dns.GetHostEntry(ip);
                    //        name = hostEntry.HostName;
                    //    }
                    //    catch (SocketException ex)
                    //    {
                    //        name = "?";
                    //    }
                    //    Console.WriteLine("{0} ({1}) is up: ({2} ms)", ip, name, e.Reply.RoundtripTime);
                    //}
                    //else
                    //{
                    activeInterfaces.Add(ip);
                    Console.WriteLine("{0} is up: ({1} ms)", ip, e.Reply.RoundtripTime);
                    //}
                    lock (lockObj)
                    {
                        upCount++;
                    }
                }
                else if (e.Reply == null)
                {
                    Console.WriteLine("Pinging {0} failed. (Null Reply object?)", ip);
                }
                countdown.Signal();
            }
            catch (Exception exp)
            {
                Console.WriteLine("Here you go...");
            }

        }


        [HttpGet]
        [Route("api/pc/getOnlinePCs")]
        public List<string> GetOnlinePCs()
        {

            activeInterfaces.Clear();
            //List<string> activeInterfaces=new List<string>();
            string ipBase = "";

            var host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (var ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    ipBase = ip.ToString().Substring(0, (ip.ToString().LastIndexOf(".") + 1));//"10.22.4.";

                }
            }


            countdown = new CountdownEvent(1);
            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 2; i < 254; i++)
            {
                string ip = ipBase + i.ToString();

                //var tcpClient = new TcpClient();
                //tcpClient.Connected += new PingCompletedEventHandler(p_PingCompleted);
                Ping ping = new Ping();
                ping.PingCompleted += new PingCompletedEventHandler(p_PingCompleted);
                countdown.AddCount();
                ping.SendAsync(ip, 20, ip);
            }
            countdown.Signal();
            countdown.Wait();
            sw.Stop();
            TimeSpan span = new TimeSpan(sw.ElapsedTicks);
            Console.WriteLine("Took {0} milliseconds. {1} hosts active.", sw.ElapsedMilliseconds, upCount);
            Console.ReadLine();
     

            return activeInterfaces;
        }

我不认为 SO 线程中提供的解决方案已过期,而是我会犯一个小的逻辑错误,因为我是前端人员。谢谢!

编辑

根据专家评论,我将 SendAsync 代码包装在 try/catch 中,最后阻塞为

              try
                {
                    Ping ping = new Ping();
                    ping.PingCompleted += new PingCompletedEventHandler(p_PingCompleted);
                    countdown.AddCount();
                    ping.SendAsync(ip, 20, ip);
                }
                catch(Exception exception)
                {
                    Console.WriteLine($"Exception on {ip} .Technical details: {exception}");
                }
                finally
                {
                    countdown.AddCount();
                }

但是当我调试代码时,它总是落入 finally 块。不要异常阻塞,在 253 ping 迭代完成后,再次无限循环!@Evk 和 @jdweng 请帮忙!

@Evk 这里是它被卡住的图像 在此处输入图像描述

标签: c#networkingping

解决方案


Ping SendAsync 没有按照您的预期进行,您可以释放资源,但是您需要自己处理从另一个线程返回的答案,您需要挂钩 PingCompleted 来处理答案。

你最好通过调用 ping 和在你的方法中为你的方法创建一个异步方法,并通过自己实现它在异步方法中调用你的方法 https://docs.microsoft.com/en-us/dotnet/standard/parallel-任务中的编程/如何包装 eap 模式

Ping pingSender = new Ping ();

// When the PingCompleted event is raised,
// the PingCompletedCallback method is called.
pingSender.PingCompleted += new PingCompletedEventHandler (PingCompletedCallback);

// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte [] buffer = Encoding.ASCII.GetBytes (data);

// Wait 12 seconds for a reply.
int timeout = 12000;

// Set options for transmission:
// The data can go through 64 gateways or routers
// before it is destroyed, and the data packet
// cannot be fragmented.
PingOptions options = new PingOptions (64, true);

// Send the ping asynchronously.
// Use the waiter as the user token.
// When the callback completes, it can wake up this thread.
pingSender.SendAsync (who, timeout, buffer, options, waiter);

// Prevent this example application from ending.
// A real application should do something useful
// when possible.
waiter.WaitOne ();

推荐阅读