-
-
Save facemao3/8f5b4616d8227b31749a7f180bbca8cc to your computer and use it in GitHub Desktop.
Asynchronous Ping/DNSResolver by C#. Also PowerShell OnTheFly compile Asynchronous Ping
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Main() | |
{ | |
var computerName = Enumerable.Range(1, 250).Select(x => "192.10.10." + x).ToArray(); | |
// var computerName = Util.Cache(() => Enumerable.Range(1, 254).SelectMany(i => Enumerable.Range(10, 4).SelectMany(j => new[] { $"192.10.{j}.{i}" })).ToArray()); | |
var sw = Stopwatch.StartNew(); | |
NetworkInformationExtensions.PingAsync(computerName, TimeSpan.FromMilliseconds(1), false).Result.Where(x => x.Status == IPStatus.Success); | |
sw.Elapsed.TotalMilliseconds.Dump("Resolve = false, PingTimeout = 1"); | |
sw.Restart(); | |
NetworkInformationExtensions.PingAsync(computerName, false).Result.Where(x => x.Status == IPStatus.Success); | |
sw.Elapsed.TotalMilliseconds.Dump("Resolve = false, PingTimeout = 10"); | |
sw.Restart(); | |
NetworkInformationExtensions.PingAsync(computerName, TimeSpan.FromMilliseconds(100), false).Result.Where(x => x.Status == IPStatus.Success); | |
sw.Elapsed.TotalMilliseconds.Dump("Resolve = false, PingTimeout = 100"); | |
sw.Restart(); | |
NetworkInformationExtensions.PingAsync(computerName, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(10)).Result.Where(x => x.Status == IPStatus.Success); | |
sw.Elapsed.TotalMilliseconds.Dump("Resolve = true, PingTimeout = 10, DnsTimeOut = 10"); | |
sw.Restart(); | |
NetworkInformationExtensions.PingAsync(computerName).Result.Where(x => x.Status == IPStatus.Success); | |
sw.Elapsed.TotalMilliseconds.Dump("Resolve = true, PingTimeout = 10, DnsTimeOut = 20"); | |
sw.Restart(); | |
NetworkInformationExtensions.PingAsync(computerName, TimeSpan.FromMilliseconds(20), TimeSpan.FromMilliseconds(20)).Result.Where(x => x.Status == IPStatus.Success); | |
sw.Elapsed.TotalMilliseconds.Dump("Resolve = true, PingTimeout = 20, DnsTimeOut = 20"); | |
sw.Restart(); | |
NetworkInformationExtensions.PingAsync(computerName, TimeSpan.FromMilliseconds(20), TimeSpan.FromSeconds(1)).Result.Where(x => x.Status == IPStatus.Success); | |
sw.Elapsed.TotalMilliseconds.Dump("Resolve = true, PingTimeout = 20, DnsTimeOut = 1000"); | |
sw.Restart(); | |
NetworkInformationExtensions.PingAsync(computerName, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)).Result.Where(x => x.Status == IPStatus.Success); | |
sw.Elapsed.TotalMilliseconds.Dump("Resolve = true, PingTimeout = 1000, DnsTimeOut = 1000"); | |
sw.Restart(); | |
NetworkInformationExtensions.PingAsync(computerName, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(1)).Result.Where(x => x.Status == IPStatus.Success); | |
sw.Elapsed.TotalMilliseconds.Dump("Resolve = true, PingTimeout = 2000, DnsTimeOut = 1000"); | |
sw.Restart(); | |
NetworkInformationExtensions.PingAsync(computerName, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2)).Result.Where(x => x.Status == IPStatus.Success); | |
sw.Elapsed.TotalMilliseconds.Dump("Resolve = true, PingTimeout = 1000, DnsTimeOut = 2000"); | |
} | |
public class DnsResponse | |
{ | |
public string HostName { get; private set; } | |
public IPAddress IPAddress { get; private set; } | |
public DnsResponse(string hostName, IPAddress ip) | |
{ | |
this.HostName = hostName; | |
this.IPAddress = ip; | |
} | |
} | |
public class DnsResolver | |
{ | |
public static DnsResponse ResolveIP(IPAddress ip, TimeSpan timeout) | |
{ | |
Func<IPAddress, IPHostEntry> callback = s => Dns.GetHostEntry(s); | |
var result = callback.BeginInvoke(ip, null, null); | |
if (!result.AsyncWaitHandle.WaitOne(timeout, false)) | |
{ | |
return new DnsResponse(ip.ToString(), ip); | |
} | |
var hostEntry = callback.EndInvoke(result); | |
return new DnsResponse(hostEntry.HostName, ip); | |
} | |
public static DnsResponse ResolveHostName(string hostNameOrAddress, TimeSpan timeout) | |
{ | |
Func<string, IPHostEntry> callback = s => Dns.GetHostEntry(s); | |
var result = callback.BeginInvoke(hostNameOrAddress, null, null); | |
if (!result.AsyncWaitHandle.WaitOne(timeout, false)) | |
{ | |
return new DnsResponse(hostNameOrAddress, null); | |
} | |
var hostEntry = callback.EndInvoke(result); | |
var ip = hostEntry.AddressList.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork); | |
return new DnsResponse(hostNameOrAddress, ip); | |
} | |
} | |
public class PingResponse | |
{ | |
public string HostNameOrAddress { get; set; } | |
public IPAddress IPAddress { get; set; } | |
public IPStatus Status { get; set; } | |
public bool IsSuccess { get; set; } | |
public long RoundTripTime { get; set; } | |
public bool IsResolved { get; set; } | |
} | |
public class NetworkInformationExtensions | |
{ | |
private static readonly byte[] _buffer = new byte[16]; | |
private static readonly PingOptions _options = new PingOptions(64, false); | |
private static readonly TimeSpan _pingTimeout = TimeSpan.FromMilliseconds(10); | |
private static readonly TimeSpan _dnsTimeout = TimeSpan.FromMilliseconds(20); | |
private static bool _resolveDns = true; | |
public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress) | |
{ | |
return await PingAsync(hostNameOrAddress, _pingTimeout, _resolveDns, _dnsTimeout); | |
} | |
public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, TimeSpan pingTimeout) | |
{ | |
return await PingAsync(hostNameOrAddress, pingTimeout, _resolveDns, _dnsTimeout); | |
} | |
public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, bool resolveDns) | |
{ | |
return await PingAsync(hostNameOrAddress, _pingTimeout, resolveDns, _dnsTimeout); | |
} | |
public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, TimeSpan pingTimeout, bool resolveDns) | |
{ | |
return await PingAsync(hostNameOrAddress, pingTimeout, resolveDns, _dnsTimeout); | |
} | |
public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, TimeSpan pingTimeout, TimeSpan dnsTimeout) | |
{ | |
return await PingAsync(hostNameOrAddress, pingTimeout, _resolveDns, _dnsTimeout); | |
} | |
private static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, TimeSpan pingTimeout, bool resolveDns, TimeSpan dnsTimeout) | |
{ | |
var pingResult = await Task.WhenAll(hostNameOrAddress.Select(async x => | |
{ | |
// Resolve only when incoming is HostName. | |
IPAddress ip = null; | |
DnsResponse resolve = null; | |
var isIpAddress = IPAddress.TryParse(x, out ip); | |
if (!isIpAddress) | |
{ | |
resolve = DnsResolver.ResolveHostName(x, dnsTimeout); | |
ip = resolve.IPAddress; | |
} | |
// Execute PingAsync | |
PingReply reply = null; | |
using (var ping = new Ping()) | |
{ | |
try | |
{ | |
reply = await ping.SendPingAsync(ip, (int)pingTimeout.TotalMilliseconds, _buffer, _options); | |
} | |
catch | |
{ | |
// ping throw should never stop operation. just return null. | |
} | |
} | |
// set RoundtripTime | |
long roundTripTime = 0; | |
if (reply != null) roundTripTime = reply.RoundtripTime; | |
// set Status | |
var status = IPStatus.DestinationHostUnreachable; | |
if (reply != null) status = reply.Status; | |
// set IsSuccess | |
var isSuccess = status == IPStatus.Success; | |
// return when PingFailed || HostName || OmitResolveDns | |
if (!isSuccess || !isIpAddress || !resolveDns) | |
return new PingResponse | |
{ | |
HostNameOrAddress = x, | |
IPAddress = ip, | |
Status = status, | |
RoundTripTime = roundTripTime, | |
IsSuccess = isSuccess, | |
IsResolved = resolve != null, | |
}; | |
// Resolve Dns only for success host entry. | |
var host = x; | |
resolve = DnsResolver.ResolveIP(ip, dnsTimeout); | |
if (resolve != null) host = resolve.HostName; | |
return new PingResponse | |
{ | |
HostNameOrAddress = host, | |
IPAddress = ip, | |
Status = status, | |
RoundTripTime = roundTripTime, | |
IsSuccess = true, | |
IsResolved = resolve != null, | |
}; | |
}).ToArray()); | |
return pingResult; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$asm = "System", "System.Net", "System.Linq", "System.Threading.Tasks", "System.Net.NetworkInformation" | |
$source = @" | |
using System; | |
using System.Net; | |
using System.Threading.Tasks; | |
using System.Linq; | |
using System.Net.NetworkInformation; | |
using System.Net.Sockets; | |
namespace PingEx | |
{ | |
public class DnsResponse | |
{ | |
public string HostName { get; private set; } | |
public IPAddress IPAddress { get; private set; } | |
public DnsResponse(string hostName, IPAddress ip) | |
{ | |
this.HostName = hostName; | |
this.IPAddress = ip; | |
} | |
} | |
public class DnsResolver | |
{ | |
public static DnsResponse ResolveIP(IPAddress ip, TimeSpan timeout) | |
{ | |
Func<IPAddress, IPHostEntry> callback = s => Dns.GetHostEntry(s); | |
var result = callback.BeginInvoke(ip, null, null); | |
if (!result.AsyncWaitHandle.WaitOne(timeout, false)) | |
{ | |
return new DnsResponse(ip.ToString(), ip); | |
} | |
var hostEntry = callback.EndInvoke(result); | |
return new DnsResponse(hostEntry.HostName, ip); | |
} | |
public static DnsResponse ResolveHostName(string hostNameOrAddress, TimeSpan timeout) | |
{ | |
Func<string, IPHostEntry> callback = s => Dns.GetHostEntry(s); | |
var result = callback.BeginInvoke(hostNameOrAddress, null, null); | |
if (!result.AsyncWaitHandle.WaitOne(timeout, false)) | |
{ | |
return new DnsResponse(hostNameOrAddress, null); | |
} | |
var hostEntry = callback.EndInvoke(result); | |
var ip = hostEntry.AddressList.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork); | |
return new DnsResponse(hostNameOrAddress, ip); | |
} | |
} | |
public class PingResponse | |
{ | |
public string HostNameOrAddress { get; set; } | |
public IPAddress IPAddress { get; set; } | |
public IPStatus Status { get; set; } | |
public bool IsSuccess { get; set; } | |
public long RoundTripTime { get; set; } | |
public bool IsResolved { get; set; } | |
} | |
public class NetworkInformationExtensions | |
{ | |
private static readonly byte[] _buffer = new byte[16]; | |
private static readonly PingOptions _options = new PingOptions(64, false); | |
private static readonly TimeSpan _pingTimeout = TimeSpan.FromMilliseconds(10); | |
private static readonly TimeSpan _dnsTimeout = TimeSpan.FromMilliseconds(20); | |
private static bool _resolveDns = true; | |
public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress) | |
{ | |
return await PingAsync(hostNameOrAddress, _pingTimeout, _resolveDns, _dnsTimeout); | |
} | |
public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, TimeSpan pingTimeout) | |
{ | |
return await PingAsync(hostNameOrAddress, pingTimeout, _resolveDns, _dnsTimeout); | |
} | |
public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, bool resolveDns) | |
{ | |
return await PingAsync(hostNameOrAddress, _pingTimeout, resolveDns, _dnsTimeout); | |
} | |
public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, TimeSpan pingTimeout, bool resolveDns) | |
{ | |
return await PingAsync(hostNameOrAddress, pingTimeout, resolveDns, _dnsTimeout); | |
} | |
public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, TimeSpan pingTimeout, TimeSpan dnsTimeout) | |
{ | |
return await PingAsync(hostNameOrAddress, pingTimeout, _resolveDns, _dnsTimeout); | |
} | |
private static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, TimeSpan pingTimeout, bool resolveDns, TimeSpan dnsTimeout) | |
{ | |
var pingResult = await Task.WhenAll(hostNameOrAddress.Select(async x => | |
{ | |
// Resolve only when incoming is HostName. | |
IPAddress ip = null; | |
DnsResponse resolve = null; | |
var isIpAddress = IPAddress.TryParse(x, out ip); | |
if (!isIpAddress) | |
{ | |
resolve = DnsResolver.ResolveHostName(x, dnsTimeout); | |
ip = resolve.IPAddress; | |
} | |
// Execute PingAsync | |
PingReply reply = null; | |
using (var ping = new Ping()) | |
{ | |
try | |
{ | |
reply = await ping.SendPingAsync(ip, (int)pingTimeout.TotalMilliseconds, _buffer, _options); | |
} | |
catch | |
{ | |
// ping throw should never stop operation. just return null. | |
} | |
} | |
// set RoundtripTime | |
long roundTripTime = 0; | |
if (reply != null) roundTripTime = reply.RoundtripTime; | |
// set Status | |
var status = IPStatus.DestinationHostUnreachable; | |
if (reply != null) status = reply.Status; | |
// set IsSuccess | |
var isSuccess = status == IPStatus.Success; | |
// return when PingFailed || HostName || OmitResolveDns | |
if (!isSuccess || !isIpAddress || !resolveDns) | |
return new PingResponse | |
{ | |
HostNameOrAddress = x, | |
IPAddress = ip, | |
Status = status, | |
RoundTripTime = roundTripTime, | |
IsSuccess = isSuccess, | |
IsResolved = resolve != null, | |
}; | |
// Resolve Dns only for success host entry. | |
var host = x; | |
resolve = DnsResolver.ResolveIP(ip, dnsTimeout); | |
if (resolve != null) host = resolve.HostName; | |
return new PingResponse | |
{ | |
HostNameOrAddress = host, | |
IPAddress = ip, | |
Status = status, | |
RoundTripTime = roundTripTime, | |
IsSuccess = true, | |
IsResolved = resolve != null, | |
}; | |
}).ToArray()); | |
return pingResult; | |
} | |
} | |
} | |
"@ | |
Add-Type -TypeDefinition $source -ReferencedAssemblies $asm; | |
$computerName = 1..254 | %{"192.168.10.$_"}; | |
$computerName = 1..254 | %{"192.168.10.$_", "192.168.20.$_", "172.16.30.$_", "172.30.40.$_"}; | |
# [PingEx.NetworkInformationExtensions]::PingAsync($computerName).Result; | |
measure-command {[PingEx.NetworkInformationExtensions]::PingAsync($computerName, [TimeSpan]::FromMilliseconds(1), $false).Result;} | select TotalMilliseconds | |
measure-command {[PingEx.NetworkInformationExtensions]::PingAsync($computerName, $false).Result;} | |
measure-command {[PingEx.NetworkInformationExtensions]::PingAsync($computerName, [TimeSpan]::FromMilliseconds(100), $false).Result;} | select TotalMilliseconds | |
measure-command {[PingEx.NetworkInformationExtensions]::PingAsync($computerName, [TimeSpan]::FromMilliseconds(10), [TimeSpan]::FromMilliseconds(10)).Result;} | select TotalMilliseconds | |
measure-command {[PingEx.NetworkInformationExtensions]::PingAsync($computerName).Result;} | select TotalMilliseconds | |
measure-command {[PingEx.NetworkInformationExtensions]::PingAsync($computerName, [TimeSpan]::FromMilliseconds(20), [TimeSpan]::FromMilliseconds(20)).Result;} | select TotalMilliseconds | |
measure-command {[PingEx.NetworkInformationExtensions]::PingAsync($computerName, [TimeSpan]::FromMilliseconds(20), [TimeSpan]::FromSeconds(1)).Result;} | select TotalMilliseconds | |
measure-command {[PingEx.NetworkInformationExtensions]::PingAsync($computerName, [TimeSpan]::FromSeconds(1), [TimeSpan]::FromSeconds(1)).Result;} | select TotalMilliseconds | |
measure-command {[PingEx.NetworkInformationExtensions]::PingAsync($computerName, [TimeSpan]::FromSeconds(2), [TimeSpan]::FromSeconds(1)).Result;} | select TotalMilliseconds | |
measure-command {[PingEx.NetworkInformationExtensions]::PingAsync($computerName, [TimeSpan]::FromSeconds(1), [TimeSpan]::FromSeconds(2)).Result;} | select TotalMilliseconds | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment