代码之家  ›  专栏  ›  技术社区  ›  Stefan Steiger Marco van de Voort

异步Ping:如何避免内存不足异常?

  •  1
  • Stefan Steiger Marco van de Voort  · 技术社区  · 15 年前

    所以我向子网中的所有IP地址发送一个ping。

    问题是,如果我只扫描192.168.0,它可以正常工作。 *,然后我得到一个“内存不足”异常。

        static void Main(string[] args)
        { 
            string strFromIP = "192.168.0.1";
            string strToIP = "192.168.255.255";
    
            Oyster.Math.IntX omiFromIP = 0;
            Oyster.Math.IntX omiToIP = 0;
            IsValidIP(strFromIP, ref omiFromIP);
            IsValidIP(strToIP, ref omiToIP);
            for (Oyster.Math.IntX omiThisIP = omiFromIP; omiThisIP <= omiToIP; ++omiThisIP)
            {
                Console.WriteLine(IPn2IPv4(omiThisIP));
                System.Net.IPAddress sniIPaddress = System.Net.IPAddress.Parse(IPn2IPv4(omiThisIP));
                SendPingAsync(sniIPaddress);
            }
    
            Console.WriteLine(" --- Press any key to continue --- ");
            Console.ReadKey();
        } // Main
    
    
        // http://pberblog.com/post/2009/07/21/Multithreaded-ping-sweeping-in-VBnet.aspx
        // http://www.cyberciti.biz/faq/how-can-ipv6-address-used-with-webbrowser/#comments
        // http://www.kloth.net/services/iplocate.php
        // http://bytes.com/topic/php/answers/829679-convert-ipv4-ipv6
        // http://stackoverflow.com/questions/1434342/ping-class-sendasync-help
        public static void SendPingAsync(System.Net.IPAddress sniIPaddress)
        {
            int iTimeout = 5000;
            System.Net.NetworkInformation.Ping myPing = new System.Net.NetworkInformation.Ping();
            System.Net.NetworkInformation.PingOptions parmPing = new System.Net.NetworkInformation.PingOptions();
    
            System.Threading.AutoResetEvent waiter = new System.Threading.AutoResetEvent(false);
            myPing.PingCompleted += new System.Net.NetworkInformation.PingCompletedEventHandler(AsyncPingCompleted);
            string data = "ABC";
            byte[] dataBuffer = Encoding.ASCII.GetBytes(data);
    
            parmPing.DontFragment = true;
            parmPing.Ttl = 32;
    
            myPing.SendAsync(sniIPaddress, iTimeout, dataBuffer, parmPing, waiter);
            //waiter.WaitOne();
        }
    
    
        private static void AsyncPingCompleted(Object sender, System.Net.NetworkInformation.PingCompletedEventArgs e)
        {
    
            System.Net.NetworkInformation.PingReply reply = e.Reply;
            ((System.Threading.AutoResetEvent)e.UserState).Set();
            if (reply.Status == System.Net.NetworkInformation.IPStatus.Success)
            {
                Console.WriteLine("Address: {0}", reply.Address.ToString());
                Console.WriteLine("Roundtrip time: {0}", reply.RoundtripTime);
            }
        }
    
    6 回复  |  直到 15 年前
        1
  •  2
  •   Joel Mueller    15 年前

    根据 this thread , System.Net.NetworkInformation.Ping

    该人员使用的解决方法是使用原始套接字编写自己的实现。当然,在F#中不必这样做,但这样做有很多好处。

        2
  •  2
  •   jgauffin    15 年前

    第一次:第一次只开始大约1000个ping(在Main的循环中)

    第二:将下列参数移到程序类(成员变量)

    Oyster.Math.IntX omiFromIP = 0; 
    Oyster.Math.IntX omiToIP = 0;
    Oyster.Math.IntX omiCurrentIp = 0;
    object syncLock = new object();
    

    第三:在下面的步骤中:

    public void AsyncPingCompleted (bla bla bla)
    {
        //[..other code..]
    
        lock (syncLock) 
        {
            if (omiToIP < omiCurrentIp)
            {
               ++omiCurrentIp;
               System.Net.IPAddress sniIPaddress = System.Net.IPAddress.Parse(IPn2IPv4(omiCurrentIp)); 
               SendPingAsync(sniIPaddress); 
            }
        }
    }
    

    用完整的代码示例更新

    public class Example
    {
        // Number of pings that can be pending at the same time
        private const int InitalRequests = 10000;
    
        // variables from your Main method
        private Oyster.Math.IntX _omiFromIP = 0;
        private Oyster.Math.IntX _omiToIP = 0;
        private Oyster.Math.IntX _omiCurrentIp = 0;
    
        // synchronoize so that two threads
        // cannot ping the same IP.
        private object _syncLock = new object();
    
        static void Main(string[] args)
        {
            string strFromIP = "192.168.0.1";
            string strToIP = "192.168.255.255";
    
            IsValidIP(strFromIP, ref _omiFromIP);
            IsValidIP(strToIP, ref _omiToIP);
            for (_omiCurrentIp = _omiFromIP; _omiCurrentIp <= _omiFromIP + InitalRequests; ++_omiCurrentIp)
            {
                Console.WriteLine(IPn2IPv4(_omiCurrentIp));
                System.Net.IPAddress sniIPaddress = System.Net.IPAddress.Parse(IPn2IPv4(_omiCurrentIp));
                SendPingAsync(sniIPaddress);
            }
    
            Console.WriteLine(" --- Press any key to continue --- ");
            Console.ReadKey();
        } // Main
    
    
        // http://pberblog.com/post/2009/07/21/Multithreaded-ping-sweeping-in-VBnet.aspx
        // http://www.cyberciti.biz/faq/how-can-ipv6-address-used-with-webbrowser/#comments
        // http://www.kloth.net/services/iplocate.php
        // http://bytes.com/topic/php/answers/829679-convert-ipv4-ipv6
        // http://stackoverflow.com/questions/1434342/ping-class-sendasync-help
        public void SendPingAsync(System.Net.IPAddress sniIPaddress)
        {
            int iTimeout = 5000;
            System.Net.NetworkInformation.Ping myPing = new System.Net.NetworkInformation.Ping();
            System.Net.NetworkInformation.PingOptions parmPing = new System.Net.NetworkInformation.PingOptions();
    
            System.Threading.AutoResetEvent waiter = new System.Threading.AutoResetEvent(false);
            myPing.PingCompleted += new System.Net.NetworkInformation.PingCompletedEventHandler(AsyncPingCompleted);
            string data = "ABC";
            byte[] dataBuffer = Encoding.ASCII.GetBytes(data);
    
            parmPing.DontFragment = true;
            parmPing.Ttl = 32;
    
            myPing.SendAsync(sniIPaddress, iTimeout, dataBuffer, parmPing, waiter);
            //waiter.WaitOne();
        }
    
    
        private void AsyncPingCompleted(Object sender, System.Net.NetworkInformation.PingCompletedEventArgs e)
        {
    
            System.Net.NetworkInformation.PingReply reply = e.Reply;
            ((System.Threading.AutoResetEvent)e.UserState).Set();
            if (reply.Status == System.Net.NetworkInformation.IPStatus.Success)
            {
                Console.WriteLine("Address: {0}", reply.Address.ToString());
                Console.WriteLine("Roundtrip time: {0}", reply.RoundtripTime);
            }
    
    
            // Keep starting those async pings until all ips have been invoked.
            lock (_syncLock)
            {
                if (_omiToIP < _omiCurrentIp)
                {
                    ++_omiCurrentIp;
                    System.Net.IPAddress sniIPaddress = System.Net.IPAddress.Parse(IPn2IPv4(_omiCurrentIp));
                    SendPingAsync(sniIPaddress);
                }
            }
        }        
    }
    
        3
  •  1
  •   Community Mohan Dere    9 年前

    63K ping请求几乎同时进行

    我会再次调查 the Task Parallel Library ,的 Parallel.For the Task<T> 会让你轻松些。

    there is hope .

        4
  •  1
  •   BlackBear    12 年前

    我做了类似的事情。我解决项目问题的方法是将ping实例转换为IDisposable:

    (myPing as IDisposable).Dispose()
    

    很有魅力。

        5
  •  0
  •   dbasnett    15 年前

    伪码

    do
    
    if pings_running > 100 then
    sleep 100ms.
    else
    start ping
    endif
    
    loop while morepings
    
        6
  •  0
  •   abatishchev Karl Johan    15 年前

    http://www.codeproject.com/KB/cs/c__ip_scanner.aspx

    我所需要做的就是让它在调试时线程安全。

    void Add( string m )
    {
        Invoke(new MethodInvoker(
            delegate
            {
                add.Items.Add(m);
            }));
        //add.Items.Add( m );
    }
    

    Private Sub Add(m As String)
        Invoke(New MethodInvoker(Function() Do
            add.Items.Add(m)
        End Function))
        'add.Items.Add(m);'
    End Sub