0

我正在尝试编写一种方法来确定我的域中的哪些计算机是“非活动的”。我能够让它工作的唯一方法是尝试使用以下方法获取计算机的 IP 地址:

Dns.GetHostAddresses( computerName )

如果计算机处于“非活动状态”,它会抛出一个System.Net.Sockets.SocketException,然后我可以捕获该计算机并将其添加到我的非活动计算机数据表中。这种方法的问题在于它非常缓慢。通过我的 500 台计算机的 Windows 域,大约 300 台计算机处于“非活动状态”,通过这种方法对它们进行排序需要将近 30 分钟。有没有人建议如何判断在我的 Windows 域中注册的计算机是否处于活动状态?

我也尝试通过 ping 我列表中的所有计算机来做到这一点,但是当尝试 ping 一台“非活动”计算机时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

我有一个类似的要求,因为我想扫描网络中的 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 回答
0

想通了这个问题......终于!我使用了一个Parallel.ForEach循环,它解决了我所有的问题。正如六个字母变量所建议的那样,我不得不在访问列表时使用锁定。工作得很好!

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 回答