【问题标题】:How to determine if a computer in my Windows Domain is "active"如何确定我的 Windows 域中的计算机是否“活动”
【发布时间】:2012-07-07 07:18:32
【问题描述】:

我正在尝试编写一种方法来确定我域中的哪些计算机处于“非活动状态”。我能够让它工作的唯一方法是尝试使用以下方法获取计算机的 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 );
            }

【问题讨论】:

  • 您有什么理由按顺序运行而不是使用多个线程?
  • 在“不响应网络请求”中处于非活动状态?
  • 在一台不再存在的机器中处于非活动状态,但之前存在并因此而出现。
  • Yahia,我只是不使用多线程,因为它不方便。我希望有一种更简洁的方法来处理问题而不会捕获异常。
  • 您的线程版本可能会在访问列表时使用一些锁定。您可能还需要考虑速率限制,以避免最终出现 500 个运行中线程的情况。

标签: c# exception networking dns ping


【解决方案1】:

我有一个类似的需求,我想扫描网络以查找 IP 地址以确定正在使用的地址。

我做了几个假设,首先,Ping 不会在大多数设备上被阻塞,其次我们只处理特定范围的地址 EG 192.168.x.x

这不是最干净的代码,只是一个快速而肮脏的示例,但以下将作为控制台应用程序运行,并演示如何将线程与 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;
        }

    }
} 

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2010-09-17
      • 2010-11-20
      • 2012-12-26
      • 2018-01-20
      • 2020-06-19
      • 2015-08-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-04
      相关资源
      最近更新 更多