0

ドメイン内のどのコンピュータが「非アクティブ」であるかを判断するメソッドを作成しようとしています。これを機能させることができた唯一の方法は、次を使用してコンピューターのIPアドレスを取得しようとすることです。

Dns.GetHostAddresses( computerName )

コンピューターが「非アクティブ」の場合、それをスローして、System.Net.Sockets.SocketExceptionそのコンピューターをキャッチして、非アクティブなコンピューターの DataTable に追加できます。この方法の問題点は、非常に遅いことです。私の Windows ドメインを 500 台のコンピューターで調べると、約 300 台が「非アクティブ」であり、この方法でそれらを並べ替えるのに約 30 分かかります。Windows ドメインに登録されているコンピューターがアクティブかどうかを確認する方法について、誰か提案はありますか?

また、リスト内のすべてのコンピューターに ping を実行してこれを実行しようとしましたが、「非アクティブ」なコンピューターに ping を実行しようとすると、 a がスローされ、System.Net.NetworkInformation.PingExceptionこれをキャッチして同じ方法で処理する必要があります。これにより、このプロセスの実行時間も 30 分近くになります。

これが私のコードです。

public void findInactiveComputers( string customerName, string domain )
        {
            DirectoryEntry entry = new DirectoryEntry( domain );
            DirectorySearcher searcher = new DirectorySearcher( entry );
            searcher.Filter = ("(objectClass=computer)");
            searcher.SizeLimit = int.MaxValue;
            searcher.PageSize = int.MaxValue;

            // Removes the inactive computers from the DataTable that associated with the customer.
            if( _InactiveComputers.Rows.Count != 0 )
            {
                _InactiveComputers.AsEnumerable().Where( cust => cust["CustomerName"].ToString()
                    .Equals( customerName, StringComparison.InvariantCultureIgnoreCase ) )
                    .ToList().ForEach( comp => comp.Delete() );
            }

            foreach( SearchResult result in searcher.FindAll() )
            {
                if( result.GetDirectoryEntry().Name.StartsWith( "CN=" ) )
                {
                    string computerName = result.GetDirectoryEntry().Name.Remove( 0, "CN=".Length );

                    try
                    { 
                        Dns.GetHostAddresses( computerName );
                    }

                    catch( SocketException )
                    {
                        DataRow newRow = _InactiveComputers.NewRow();
                        newRow["ComputerName"] = computerName;
                        newRow["CustomerName"] = customerName;
                        _InactiveComputers.Rows.Add( newRow );
                    }
                }
            }

            Properties.Settings.Default.InvalidComputers = _InactiveComputers;
            Properties.Settings.Default.Save();
        }

編集:

複数のスレッドを使用してタスクを実行しようとしましたが、待機時間が依然として非常に長いです (現在実行していますが、まだ完了していません)。

これが私がそれをどのように実装したかです。パフォーマンスを改善するための提案はありますか?

List<string> inactiveComputerNames = new List<string>();

            foreach( SearchResult result in searcher.FindAll() )
            {
                new Thread( delegate()
                    {
                        if( result.GetDirectoryEntry().Name.StartsWith( "CN=" ) )
                        {
                            string computerName = result.GetDirectoryEntry().Name.Remove( 0, "CN=".Length );

                            try
                            {
                                Dns.GetHostAddresses( computerName );
                            }

                            catch( SocketException )
                            {
                                inactiveComputerNames.Add( computerName );
                            }
                        }
                    } ).Start();
            }

            foreach( string computerName in inactiveComputerNames )
            {
                DataRow newRow = _InactiveComputers.NewRow();
                newRow["ComputerName"] = computerName;
                newRow["CustomerName"] = customerName;
                _InactiveComputers.Rows.Add( newRow );
            }
4

2 に答える 2

0

この問題を考え出した...最後に!私はParallel.ForEachループを使用し、すべての問題を解決しました。sixlettervariables が提案したように、リストへのアクセスをロックする必要がありました。うまくいきました!

SearchResultCollection results = searcher.FindAll();

            List<string> inactiveComputerNames = new List<string>();

            object threadLock = new object();

            Parallel.ForEach( results.OfType<SearchResult>(), result =>
            {
                if( result.GetDirectoryEntry().Name.StartsWith( "CN=" ) )
                {
                    string computerName = result.GetDirectoryEntry().Name.Remove( 0, "CN=".Length );

                    try
                    {
                        Dns.GetHostAddresses( computerName );
                    }

                    catch( SocketException )
                    {
                        lock( threadLock )
                        {
                            inactiveComputerNames.Add( computerName );
                        }
                    }
                }
            }
            );
于 2012-07-11T19:54:07.800 に答える
0

ネットワークをスキャンして IP アドレスを探し、使用中のアドレスを特定するという同様の要件がありました。

第一に、ほとんどの機器で Ping がブロックされないこと、第二に、特定の範囲のアドレス EG 192.168.xx のみを扱っていることです。

これは最もクリーンなコードではなく、簡単で汚い例ですが、以下はコンソール アプリとして実行され、Ping と組み合わせてスレッドを使用する方法の基本原則を示しています。

それが役に立てば幸い?

敬具、ウェイン

using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace NetworkPing
{
    class Program
    {

        private static int _Timeout = 120;
        private static int nextLine = 0;

        public static void Main(string[] args)
        {
            Console.WriteLine("NetworkPing!");

            //check if any command line arguments have been supplied
            if (args.Length > 0)
            {
                //parse the the arguments
                foreach ( string arg in args)
                {
                    switch( arg[1].ToString() )
                    {
                        case "?":
                            {
                                //display help topic
                                DisplayHelp();
                            }
                        break;

                        case "t":
                            {
                                //change the timout
                                _Timeout = Int32.Parse( GetParameter(arg) );
                                Console.WriteLine("Ping timeout set to {0}ms", _Timeout);
                            }
                        break;
                    }    
                }
            }


            DateTime startTime = DateTime.Now;

            IPAddress[] Adresses2 = GetAllUnicastAddresses();
            foreach (IPAddress Adres in Adresses2)
            {
                Console.WriteLine("");
                Console.WriteLine("Local IP Address: {0}", Adres);
                Console.WriteLine("Scanning IP from {0}.1 to {0}.254, awaiting results...", NetworkAddress(Adres) );

                nextLine = Console.CursorTop;

                Task[] tasks = new Task[254];

                for (int i = 0; i != 254; i++)
                {
                    //calculate the IP address for the ping
                    string ipAddressToPing = NetworkAddress( Adres ) + "." + (i+1);
                    //ping the address and check the response
                    tasks[ i ] = Task.Factory.StartNew( () => PingAddress(ipAddressToPing) );
                }

                //Block until all tasks complete.
                Task.WaitAll(tasks);

            }

            TimeSpan ts = DateTime.Now - startTime;
            Console.WriteLine("");            
            Console.WriteLine("Scan complete in {0} seconds, Press any key to continue...", ts.Seconds);
            Console.ReadKey();
        }

        private static string GetParameter( string Argument )
        {
            return Argument.Substring( Argument.LastIndexOf(":") +1);
        }

        public static void DisplayHelp()
        {
            Console.WriteLine("Usage: PingNetwork [/?] or [-?] [-t:Timeout]");
            Console.WriteLine("");
            Console.WriteLine("  {0,-12} {1}","/?","Display these usage instructions");
            Console.WriteLine("  {0,-12} {1}","-?","Display these usage instructions");
            Console.WriteLine("  {0,-12} {1}","-t:timeout","Changes the default timout from 120ms");
            Console.WriteLine("");
        }

        public static IPAddress[] GetAllUnicastAddresses()
        {
            // This works on both Mono and .NET , but there is a difference: it also
            // includes the LocalLoopBack so we need to filter that one out
            List<IPAddress> Addresses = new List<IPAddress>();
            // Obtain a reference to all network interfaces in the machine
            NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
            foreach (NetworkInterface adapter in adapters)
            {
                IPInterfaceProperties properties = adapter.GetIPProperties();
                foreach (IPAddressInformation uniCast in properties.UnicastAddresses)
                {
                    // Ignore loop-back, IPv6 and link-local
                    if (!IPAddress.IsLoopback(uniCast.Address) && uniCast.Address.AddressFamily!= AddressFamily.InterNetworkV6 && !uniCast.Address.ToString().StartsWith("169.254.") )
                        Addresses.Add(uniCast.Address);
                }

            }
            return Addresses.ToArray();
        }

        private static void PingAddress( string IPAddress )
        {
            Ping pingSender = new Ping ();
            PingOptions options = new PingOptions ();

            // Use the default Ttl value which is 128,
            // but change the fragmentation behavior.
            options.DontFragment = true;

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

            PingReply reply = pingSender.Send(IPAddress, _Timeout, buffer, options);

            if (reply.Status == IPStatus.Success)
            {
                   //set the cursor to the next line
                Console.CursorTop = nextLine;
                //        
                Console.WriteLine( IPAddress + " :OK");
                //
                nextLine++;
            }
        }


        private static string NetworkAddress( IPAddress Address )
        {
            string ipAddress = Address.ToString();
            return ipAddress.Substring( 0, ipAddress.LastIndexOf(".") );
        }

        private static string LastOctet( IPAddress Address )
        {
            string ipAddress = Address.ToString();
            return ipAddress.Substring( ipAddress.LastIndexOf(".") );
        }

        private static int _cursorX;
        private static int _cursorY;

        private static void GetCursor()
        {
            _cursorX = Console.CursorLeft;
            _cursorY = Console.CursorTop;
        }

        private static void SetCursor()
        {
            Console.CursorLeft = _cursorX;
            Console.CursorTop = _cursorY;
        }

    }
} 
于 2012-07-06T20:57:42.607 に答える