1

質問:サブネット内のすべてのコンピューターをサブネットで検索したいと思います。そのため、サブネット内のすべてのIPアドレスにpingを送信します。

問題は、192.168.0のみをスキャンした場合に正常に機能することです。"。しかし、192.168.。 *"をスキャンすると、「メモリ不足」の例外が発生します。

なんで ?スレッドを制限する必要がありますか、それとも、終了すると破棄されない新しいpingによって消費されるメモリの問題ですか、それともgc.c​​ollect()を呼び出す必要がありますか?

    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);
        }
    }
4

6 に答える 6

2

最初:最初は1000 pingのように開始します(メインのループ内)

2番目:次のパラメーターをプログラムクラス(メンバー変数)に移動します

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

3番目:AsyncPingCompletedで、下部で次のようなことを行います。

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);
            }
        }
    }        
}
于 2010-08-23T12:08:48.443 に答える
2

このスレッドによると、System.Net.NetworkInformation.Pingは非同期リクエストごとに1つのスレッドを割り当てているようで、「クラスBネットワークをpingでスイープすると、数百のスレッドが作成され、最終的にメモリ不足エラーが発生します」。

その人が使用した回避策は、rawソケットを使用して独自の実装を作成することでした。もちろん、F#でこれを行う必要はありませんが、そうすることには多くの利点があります。

于 2010-08-23T18:34:07.037 に答える
1

問題は、ほぼ同時に約63Kのping要求を生成していることだと思います。さらにメモリプロファイリングを行わないと、どの部分がメモリを消費しているかを判断するのは困難です。おそらく限られているネットワークリソースを使用しています。アクティブなpingの数を制限すると、ローカルリソースの使用が容易になり、ネットワークトラフィックも容易になります。

もう一度、タスク並列ライブラリを調べます。Parallel.For構造と組み合わせてTask<T>簡単にできるはずです。

:.Net 3.5ユーザーの場合、希望があります。

于 2010-08-23T07:37:52.283 に答える
1

私はこれに似たようなことをしました。プロジェクトで問題を解決する方法は、pingインスタンスをIDisposableにキャストすることでした。

(myPing as IDisposable).Dispose()

したがって、非同期で実行されている254個のpingインスタンス(XXX1 / 254)のリストを取得し、それらすべてがいつ報告されたかを追跡します。報告されたら、pingインスタンスのリストを反復処理し、各インスタンスで上記のコードを実行してから、リストをダンプします。

チャームのように機能します。

于 2013-08-17T18:46:26.967 に答える
0

最後に...pingはまったく必要ありません...

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
于 2010-08-24T22:44:26.367 に答える
0

擬似コード

do

if pings_running > 100 then
sleep 100ms.
else
start ping
endif

loop while morepings
于 2010-08-23T12:24:26.863 に答える