我正在尝试编写一种方法来确定我域中的哪些计算机处于“非活动状态”。我能够让它工作的唯一方法是尝试使用以下方法获取计算机的IP地址:
Dns.GetHostAddresses( computerName )
如果计算机处于“非活动状态”,它会抛出一个System.Net.Sockets.SocketException
然后我就可以捕获并将该计算机添加到我的非活动计算机的DataTable中。这种方法的问题在于它很慢。使用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 );
}
答案 0 :(得分:0)
我有类似的要求,因为我想扫描网络中的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;
}
}
}
答案 1 :(得分: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 );
}
}
}
}
);