I have 5 pc and i want to ping this pc's are available or no. So I'm using c# Ping class. Two pc are available but the other 3 pc are closed when i ping them my program wait min 7 seconds for response.
I just want to check 1000 miliseconds and returns OK or ERROR...
How can i control ping timeout?
Here my code
foreach (var item in listofpc)
{
Stopwatch timer = Stopwatch.StartNew();
try
{
Ping myPing = new Ping();
PingReply reply = myPing.Send(ServerName, 500);
if (reply != null)
{
timer.Stop();
TimeSpan timeTaken = timer.Elapsed;
Log.append("PING OK TimeTaken="+ timeTaken.ToString() + " Miliseconds", 50);
}
}
catch (Exception ex)
{
timer.Stop();
TimeSpan timeTaken = timer.Elapsed;
Log.append("PING ERROR TimeTaken=" +
timeTaken.ToString() + " Miliseconds \n" + ex.ToString(), 50);
}
}
But when i check my logs I saw response times are 2 seconds. Why ping timeout value is not working?
Any idea?
I've run into similar issues in the past, and I have some code that might help in working around this issue. I am editing it here, so it might be less than 100% correct as is, and a bit more complicated than your needs. Can you try something like this?
The hammer: (full code with test results also included below)
private static PingReply ForcePingTimeoutWithThreads(string hostname, int timeout)
{
PingReply reply = null;
var a = new Thread(() => reply = normalPing(hostname, timeout));
a.Start();
a.Join(timeout); //or a.Abort() after a timeout, but you have to take care of a ThreadAbortException in that case... brrr I like to think that the ping might go on and be successful in life with .Join :)
return reply;
}
private static PingReply normalPing(string hostname, int timeout)
{
try
{
return new Ping().Send(hostname, timeout);
}
catch //never do this kids, this is just a demo of a concept! Always log exceptions!
{
return null; //or this, in such a low level method 99 cases out of 100, just let the exception bubble up
}
}
Here is a full working sample (Tasks.WhenAny tested and working in version 4.5.2). I also learned that the elegance of Tasks comes at a more significant performance hit than I remember, but Thread.Join/Abort are too brutal for most production environments.
using System;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
//this can easily be async Task<PingReply> or even made generic (original version was), but I wanted to be able to test all versions with the same code
private static PingReply PingOrTimeout(string hostname, int timeOut)
{
PingReply result = null;
var cancellationTokenSource = new CancellationTokenSource();
var timeoutTask = Task.Delay(timeOut, cancellationTokenSource.Token);
var actionTask = Task.Factory.StartNew(() =>
{
result = normalPing(hostname, timeOut);
}, cancellationTokenSource.Token);
Task.WhenAny(actionTask, timeoutTask).ContinueWith(t =>
{
cancellationTokenSource.Cancel();
}).Wait(); //if async, remove the .Wait() and await instead!
return result;
}
private static PingReply normalPing(string hostname, int timeout)
{
try
{
return new Ping().Send(hostname, timeout);
}
catch //never do this kids, this is just a demo of a concept! Always log exceptions!
{
return null; //or this, in such a low level method 99 cases out of 100, just let the exception bubble up
}
}
private static PingReply ForcePingTimeoutWithThreads(string hostname, int timeout)
{
PingReply reply = null;
var a = new Thread(() => reply = normalPing(hostname, timeout));
a.Start();
a.Join(timeout); //or a.Abort() after a timeout... brrr I like to think that the ping might go on and be successful in life with .Join :)
return reply;
}
static byte[] b = new byte[32];
static PingOptions po = new PingOptions(64, true);
static PingReply JimiPing(string hostname, int timeout)
{
try
{
return new Ping().Send(hostname, timeout, b, po);
}
catch //never do this kids, this is just a demo of a concept! Always log exceptions!
{
return null; //or this, in such a low level method 99 cases out of 100, just let the exception bubble up
}
}
static void RunTests(Func<string, int, PingReply> timeOutPinger)
{
var stopWatch = Stopwatch.StartNew();
var expectedFail = timeOutPinger("bogusdjfkhkjh", 200);
Console.WriteLine($"{stopWatch.Elapsed.TotalMilliseconds} false={expectedFail != null}");
stopWatch = Stopwatch.StartNew();
var expectedSuccess = timeOutPinger("127.0.0.1", 200);
Console.WriteLine($"{stopWatch.Elapsed.TotalMilliseconds} true={expectedSuccess != null && expectedSuccess.Status == IPStatus.Success}");
}
static void Main(string[] args)
{
RunTests(normalPing);
RunTests(PingOrTimeout);
RunTests(ForcePingTimeoutWithThreads);
RunTests(JimiPing);
Console.ReadKey(false);
}
}
}
Some results from my testing:
>Running ping timeout tests timeout = 200. method=normal
>
> - host: bogusdjfkhkjh elapsed: 2366,9714 expected: false=False
> - host: 127.0.0.1 elapsed: 4,7249 expected: true=True
>
>Running ping timeout tests timeout = 200. method:ttl+donotfragment (Jimi)
>
> - host: bogusdjfkhkjh elapsed: 2310,836 expected: false actual: False
> - host: 127.0.0.1 elapsed: 0,7838 expected: true actual: True
>
>Running ping timeout tests timeout = 200. method:tasks
>
> - host: bogusdjfkhkjh elapsed: 234,1491 expected: false actual: False
> - host: 127.0.0.1 elapsed: 3,2829 expected: true=True
>
>Running ping timeout tests timeout = 200. method:threads
>
> - host: bogusdjfkhkjh elapsed: 200,5357 expected: false actual:False
> - host: 127.0.0.1 elapsed: 5,5956 expected: true actual: True
Caution For the Tasks version, even if the calling thread is "unblocked", the action itself, in this case the ping, might linger until it actually times out. That is why I suggest putting in a timeout for the ping command itself as well.
UPDATE Researching the why too, but thought a workaround would help you for now.
New findings:
- https://stackoverflow.com/a/34238797/8695782
- Ping timeout is unpredictable
This implementation of System.Net.NetworkInformation.Ping has been tested with
Frameworks 4.0/4.5.1/4.7.1, Console and Winforms versions.
The results are always the same (as reported below).
This is the .NET Framework Ping()
implementation of IcmpSendEcho2
and Icmp6SendEcho2
Synchronous version (Output Type is Console, but it's not relevant):
(The original version of this method does not return IPStatus
. It
returns a Class Object with full exception information. The Host Name
or address is verified/translated with the DNS resolver:
IPAddress _HostIPAddress = Dns.GetHostAddresses(HostAddress).First();
which throws a SocketException
if the Host is not found and a No such host is known notification.
The Result: BadDestination for an unknown host is set here just for this test).
static void Main(string[] args)
{
List<string> HostAdrr = new List<string>() { "192.168.2.1", "192.168.2.201",
"192.168.1.99", "200.1.1.1",
"www.microsoft.com", "www.hfkhkhfhkf.com" };
IPStatus _result;;
foreach (string _Host in HostAdrr)
{
Stopwatch timer = Stopwatch.StartNew();
_result = PingHostAddress(_Host, 1000);
timer.Stop();
Console.WriteLine("Host: {0} Elapsed time: {1}ms Result: {2}", _Host, timer.ElapsedMilliseconds, _result);
Console.WriteLine();
}
Console.ReadLine();
}
public static IPStatus PingHostAddress(string HostAddress, int timeout)
{
if (string.IsNullOrEmpty(HostAddress.Trim()))
return IPStatus.BadDestination;
byte[] buffer = new byte[32];
PingReply iReplay = null;
using (Ping iPing = new Ping())
{
try
{
//IPAddress _HostIPAddress = Dns.GetHostAddresses(HostAddress).First();
iReplay = iPing.Send(HostAddress,
timeout,
buffer,
new PingOptions(64, true));
}
catch (FormatException)
{
return IPStatus.BadDestination;
}
catch (NotSupportedException nsex)
{
throw nsex;
}
catch (PingException pex)
{
//Log/Manage pex
}
//catch (SocketException soex)
//{
//
//}
catch (Exception ex)
{
//Log/Manage ex
}
return (iReplay != null) ? iReplay.Status : IPStatus.BadDestination;
}
}
The asynchronous version uses the .SendPingAsync()
method and has the usual Async signature.
public async Task<IPStatus> PingHostAddressAsync(string HostAddress, int timeout)
{
//(...)
iReplay = await iPing.SendPingAsync(HostAddress,
timeout,
buffer,
new PingOptions(64, false));
//(...)
}
The results don't change when the async version is used. Tested with Winforms. No matter how much one tries to mess with the UI.
How to interpret the results:
Parameters:
- Host Name resolved by the Ping.Send()
method. (Resolving the Host Name beforehand doesn't change the results)
- Timeout: 1000ms (also tested 500ms and 2000ms)
- Buffer: Standard 32 Bytes
- TTL: 64
- Do Not Fragment: True
Host: 192.168.2.1 => Reachable Host in the same network.
Host: 192.168.2.201 => Unreachable (off) Host in a reachable
different subnet.
Host: 192.168.1.99 => Non existent Host in a reachable different network (hardware routed)
Host: 200.1.1.1 => Non existent Internet Address
Host: www.microsoft.com => Reachable existing resolved Internet Host Name
Host: www.hfkhkhfhkf.com => Non existent unresolvable Internet Host Name
Host: 192.168.2.1 Elapsed time: 4 Result: Success
Host: 192.168.2.201 Elapsed time: 991 Result: TimedOut
Host: 192.168.1.99 Elapsed time: 993 Result: TimedOut
Host: 200.1.1.1 Elapsed time: 997 Result: TimedOut
Host: www.microsoft.com Elapsed time: 57 Result: Success
Host: www.hfkhkhfhkf.com Elapsed time: 72 Result: BadDestination
As also noted by @PaulF in the comments, the only (persistent) anomaly
is the first response if the Host is unreachable: it's always a bit
shorter than the imposed timeout. But the Timeout is always respected (the Ping method always returns within the set time interval).