Related
In my Xamarin Forms application, I am trying to discover all devices on the local network that I am connected to. My approach is to first get the device IP address, and use to first 3 numbers to know what the gateway is (first number is always 192). And then, ping every address on that gateway. Here is my code:
public partial class MainPage : ContentPage
{
private List<Device> discoveredDevices = new List<Device>();
public MainPage()
{
InitializeComponent();
Ping_all();
}
private string GetCurrentIp()
{
IPAddress[] addresses = Dns.GetHostAddresses(Dns.GetHostName());
string ipAddress = string.Empty;
if (addresses != null && addresses[0] != null)
{
ipAddress = addresses[0].ToString();
}
else
{
ipAddress = null;
}
return ipAddress;
}
public void Ping_all()
{
string ip = GetCurrentIp();
if (ip != null)
{
//Extracting and pinging all other ip's.
string[] array = ip.Split('.');
string gateway = array[0] + "." + array[1] + "." + array[2];
for (int i = 2; i <= 255; i++)
{
string ping_var = $"{gateway}.{i}";
//time in milliseconds
Ping(ping_var, 4, 4000);
}
}
}
public void Ping(string host, int attempts, int timeout)
{
for (int i = 0; i < attempts; i++)
{
new Thread(delegate ()
{
try
{
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
ping.PingCompleted += new PingCompletedEventHandler(PingCompleted);
ping.SendAsync(host, timeout, host);
// PingCompleted never gets called
}
catch(Exception e)
{
// Do nothing and let it try again until the attempts are exausted.
// Exceptions are thrown for normal ping failurs like address lookup
// failed. For this reason we are supressing errors.
}
}).Start();
}
}
private void PingCompleted(object sender, PingCompletedEventArgs e)
{
string ip = (string)e.UserState;
if (e.Reply != null && e.Reply.Status == IPStatus.Success)
{
string hostname = GetHostName(ip);
string macaddres = GetMacAddress(ip);
var device = new Device()
{
Hostname = hostname,
IpAddress = ip,
MacAddress = macaddres
};
discoveredDevices.Add(device);
}
}
public string GetHostName(string ipAddress)
{
try
{
IPHostEntry entry = Dns.GetHostEntry(ipAddress);
if (entry != null)
{
return entry.HostName;
}
}
catch (SocketException)
{
}
return null;
}
public string GetMacAddress(string ipAddress)
{
string macAddress = string.Empty;
System.Diagnostics.Process Process = new System.Diagnostics.Process();
Process.StartInfo.FileName = "arp";
Process.StartInfo.Arguments = "-a " + ipAddress;
Process.StartInfo.UseShellExecute = false;
Process.StartInfo.RedirectStandardOutput = true;
Process.StartInfo.CreateNoWindow = true;
Process.Start();
string strOutput = Process.StandardOutput.ReadToEnd();
string[] substrings = strOutput.Split('-');
if (substrings.Length >= 8)
{
macAddress = substrings[3].Substring(Math.Max(0, substrings[3].Length - 2))
+ "-" + substrings[4] + "-" + substrings[5] + "-" + substrings[6]
+ "-" + substrings[7] + "-"
+ substrings[8].Substring(0, 2);
return macAddress;
}
else
{
return "OWN Machine";
}
}
}
I get to the part where I try to ping:
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
ping.PingCompleted += new PingCompletedEventHandler(PingCompleted);
ping.SendAsync(host, timeout, host);
But PingCompleted never gets called. No exception is thrown either. Any idea why? I'm running this on a physical Android device.
EDIT
PingCompleted started getting called for me now, not sure why it wasn't working before. But it now crashes in my GetMacAddress function on the line Process.Start(); because it can not find the resource.
I ended up using this really robust and easy to use library:
https://github.com/Yortw/RSSDP
It doesn't actually find all devices on the network, instead it uses SSDP (Simple Search Discovery Protocol) to quickly find all devices that are broadcasting a service with this protocol on the network. I filtered it to only scan devices running my app, which is what I actually needed. It takes only a second to discover my devices, which is much faster than pinging 255 addresses.
In the documentation you will see:
var deviceDefinition = new SsdpRootDevice()
{
CacheLifetime = TimeSpan.FromMinutes(30), //How long SSDP clients can cache this info.
Location = new Uri("http://mydevice/descriptiondocument.xml"), // Must point to the URL that serves your devices UPnP description document.
DeviceTypeNamespace = "my-namespace",
DeviceType = "MyCustomDevice",
FriendlyName = "Custom Device 1",
Manufacturer = "Me",
ModelName = "MyCustomDevice",
Uuid = GetPersistentUuid() // This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.
};
For the Location I set it as my device's IP. So that another device that discovers it can have the IP too. I don't think it's meant to be used this way, but it worked for me and I don't see why not.
I tested it on 2 physical Android devices.
What is the fastest and most efficient way to check for Internet connectivity in .NET?
You could use this code, which should also work in Iran and China-
public static bool CheckForInternetConnection(int timeoutMs = 10000, string url = null)
{
try
{
url ??= CultureInfo.InstalledUICulture switch
{
{ Name: var n } when n.StartsWith("fa") => // Iran
"http://www.aparat.com",
{ Name: var n } when n.StartsWith("zh") => // China
"http://www.baidu.com",
_ =>
"http://www.gstatic.com/generate_204",
};
var request = (HttpWebRequest)WebRequest.Create(url);
request.KeepAlive = false;
request.Timeout = timeoutMs;
using (var response = (HttpWebResponse)request.GetResponse())
return true;
}
catch
{
return false;
}
}
There is absolutely no way you can reliably check if there is an internet connection or not (I assume you mean access to the internet).
You can, however, request resources that are virtually never offline, like pinging google.com or something similar. I think this would be efficient.
try {
Ping myPing = new Ping();
String host = "google.com";
byte[] buffer = new byte[32];
int timeout = 1000;
PingOptions pingOptions = new PingOptions();
PingReply reply = myPing.Send(host, timeout, buffer, pingOptions);
return (reply.Status == IPStatus.Success);
}
catch (Exception) {
return false;
}
Instead of checking, just perform the action (web request, mail, ftp, etc.) and be prepared for the request to fail, which you have to do anyway, even if your check was successful.
Consider the following:
1 - check, and it is OK
2 - start to perform action
3 - network goes down
4 - action fails
5 - lot of good your check did
If the network is down your action will fail just as rapidly as a ping, etc.
1 - start to perform action
2 - if the net is down(or goes down) the action will fail
NetworkInterface.GetIsNetworkAvailable is very unreliable. Just have some VMware or other LAN connection and it will return wrong result.
Also about Dns.GetHostEntry method I were just concerned about whether test URL might be blocked in the environment where my application going to deploy.
So another way I found out is using InternetGetConnectedState method.
My code is
[System.Runtime.InteropServices.DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int Description, int ReservedValue);
public static bool CheckNet()
{
int desc;
return InternetGetConnectedState(out desc, 0);
}
Pinging google.com introduces a DNS resolution dependency. Pinging 8.8.8.8 is fine but Google is several hops away from me. All I need to do is to ping the nearest thing to me that is on the internet.
I can use Ping's TTL feature to ping hop #1, then hop #2, etc, until I get a reply from something that is on a routable address; if that node is on a routable address then it is on the internet. For most of us, hop #1 will be our local gateway/router, and hop #2 will be the first point on the other side of our fibre connection or whatever.
This code works for me, and responds quicker than some of the other suggestions in this thread because it is pinging whatever is nearest to me on the internet.
using System.Diagnostics;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Tasks;
public static async Task<bool> IsConnectedToInternetAsync()
{
const int maxHops = 30;
const string someFarAwayIpAddress = "8.8.8.8";
// Keep pinging further along the line from here to google
// until we find a response that is from a routable address
for (int ttl = 1; ttl <= maxHops; ttl++)
{
var options = new PingOptions(ttl, true);
byte[] buffer = new byte[32];
PingReply reply;
try
{
using (var pinger = new Ping())
{
reply = await pinger.SendPingAsync(someFarAwayIpAddress, 10000, buffer, options);
}
}
catch (PingException pingex)
{
Debug.Print($"Ping exception (probably due to no network connection or recent change in network conditions), hence not connected to internet. Message: {pingex.Message}");
return false;
}
string address = reply.Address?.ToString() ?? null;
Debug.Print($"Hop #{ttl} is {address}, {reply.Status}");
if (reply.Status != IPStatus.TtlExpired && reply.Status != IPStatus.Success)
{
Debug.Print($"Hop #{ttl} is {reply.Status}, hence we are not connected.");
return false;
}
if (IsRoutableAddress(reply.Address))
{
Debug.Print("That's routable, so we must be connected to the internet.");
return true;
}
}
return false;
}
private static bool IsRoutableAddress(IPAddress addr)
{
if (addr == null)
{
return false;
}
else if (addr.AddressFamily == AddressFamily.InterNetworkV6)
{
return !addr.IsIPv6LinkLocal && !addr.IsIPv6SiteLocal;
}
else // IPv4
{
byte[] bytes = addr.GetAddressBytes();
if (bytes[0] == 10)
{ // Class A network
return false;
}
else if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] <= 31)
{ // Class B network
return false;
}
else if (bytes[0] == 192 && bytes[1] == 168)
{ // Class C network
return false;
}
else
{ // None of the above, so must be routable
return true;
}
}
}
A test for internet connection by pinging Google:
new Ping().Send("www.google.com.mx").Status == IPStatus.Success
I disagree with people who are stating: "What's the point in checking for connectivity before performing a task, as immediately after the check the connection may be lost".
Surely there is a degree of uncertainty in many programming tasks we as developers undertake, but reducing the uncertainty to a level of acceptance is part of the challenge.
I recently ran into this problem making an application which including a mapping feature which linked to an on-line tile server. This functionality was to be disabled where a lack of internet connectivity was noted.
Some of the responses on this page were very good, but did however cause a lot of performance issues such as hanging, mainly in the case of the absence of connectivity.
Here is the solution that I ended up using, with the help of some of these answers and my colleagues:
// Insert this where check is required, in my case program start
ThreadPool.QueueUserWorkItem(CheckInternetConnectivity);
}
void CheckInternetConnectivity(object state)
{
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
using (WebClient webClient = new WebClient())
{
webClient.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache);
webClient.Proxy = null;
webClient.OpenReadCompleted += webClient_OpenReadCompleted;
webClient.OpenReadAsync(new Uri("<url of choice here>"));
}
}
}
volatile bool internetAvailable = false; // boolean used elsewhere in code
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
internetAvailable = true;
Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
// UI changes made here
}));
}
}
I have seen all the options listed above and the only viable option to check wither the internet is available or not is the "Ping" option.
Importing [DllImport("Wininet.dll")] and System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces() Or any other variation of the NetworkInterface class does not work well in detecting the availability of the network.These Methods only check if the network cable is plugged in or not.
The "Ping option"
if(Connection is available) returns true
if(Connection is not available and the network cable is plugged in) returns false
if(Network cable is not plugged in) Throws an exception
The NetworkInterface
if(Internet Is available)Returns True
if(Internet is not Available and Network Cable is Plugged in ) Returns True
if(Network Cable is Not Plugged in )returns false
The [DllImport("Wininet.dll")]
if(Internet Is available)Returns True
if(Internet is not Available and Network Cable is Plugged in ) Returns True
if(Network Cable is Not Plugged in )returns false
So in case of [DllImport("Wininet.dll")] and NetworkInterface There is no way of knowing if internet connection is available.
Does not solve the problem of network going down between checking and running your code
but is fairly reliable
public static bool IsAvailableNetworkActive()
{
// only recognizes changes related to Internet adapters
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
// however, this will include all adapters -- filter by opstatus and activity
NetworkInterface[] interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
return (from face in interfaces
where face.OperationalStatus == OperationalStatus.Up
where (face.NetworkInterfaceType != NetworkInterfaceType.Tunnel) && (face.NetworkInterfaceType != NetworkInterfaceType.Loopback)
select face.GetIPv4Statistics()).Any(statistics => (statistics.BytesReceived > 0) && (statistics.BytesSent > 0));
}
return false;
}
Here's how it is implemented in Android.
As a proof of concept, I translated this code to C#:
var request = (HttpWebRequest)WebRequest.Create("http://g.cn/generate_204");
request.UserAgent = "Android";
request.KeepAlive = false;
request.Timeout = 1500;
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.ContentLength == 0 && response.StatusCode == HttpStatusCode.NoContent)
{
//Connection to internet available
}
else
{
//Connection to internet not available
}
}
private bool ping()
{
System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingReply reply = pingSender.Send(address);
if (reply.Status == System.Net.NetworkInformation.IPStatus.Success)
{
return true;
}
else
{
return false;
}
}
Try to avoid testing connections by catching the exception. because we really Expect that sometimes we may lose network connection.
if (NetworkInterface.GetIsNetworkAvailable() &&
new Ping().Send(new IPAddress(new byte[] { 8, 8, 8, 8 }),2000).Status == IPStatus.Success)
//is online
else
//is offline
I wouldn't think it's impossible, just not straightforward.
I've built something like this, and yes it's not perfect, but the first step is essential: to check if there's any network connectivity. The Windows Api doesn't do a great job, so why not do a better job?
bool NetworkIsAvailable()
{
var all = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
foreach (var item in all)
{
if (item.NetworkInterfaceType == NetworkInterfaceType.Loopback)
continue;
if (item.Name.ToLower().Contains("virtual") || item.Description.ToLower().Contains("virtual"))
continue; //Exclude virtual networks set up by VMWare and others
if (item.OperationalStatus == OperationalStatus.Up)
{
return true;
}
}
return false;
}
It's pretty simple, but it really helps improve the quality of the check, especially when you want to check various proxy configurations.
So:
Check whether there's network connectivity (make this really good, maybe even have logs sent back to developers when there are false positives to improve the NetworkIsAvailable function)
HTTP Ping
(Cycle through Proxy configurations with HTTP Pings on each)
Another option is the Network List Manager API which is available for Vista and Windows 7. MSDN article here. In the article is a link to download code samples which allow you to do this:
AppNetworkListUser nlmUser = new AppNetworkListUser();
Console.WriteLine("Is the machine connected to internet? " + nlmUser.NLM.IsConnectedToInternet.ToString());
Be sure to add a reference to Network List 1.0 Type Library from the COM tab... which will show up as NETWORKLIST.
I personally find the answer of Anton and moffeltje best, but I added a check to exclude virtual networks set up by VMWare and others.
public static bool IsAvailableNetworkActive()
{
// only recognizes changes related to Internet adapters
if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()) return false;
// however, this will include all adapters -- filter by opstatus and activity
NetworkInterface[] interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
return (from face in interfaces
where face.OperationalStatus == OperationalStatus.Up
where (face.NetworkInterfaceType != NetworkInterfaceType.Tunnel) && (face.NetworkInterfaceType != NetworkInterfaceType.Loopback)
where (!(face.Name.ToLower().Contains("virtual") || face.Description.ToLower().Contains("virtual")))
select face.GetIPv4Statistics()).Any(statistics => (statistics.BytesReceived > 0) && (statistics.BytesSent > 0));
}
Introduction
In some scenarios you need to check whether internet is available or not using C# code in windows applications. May be to download or upload a file using internet in windows forms or to get some data from database which is at remote location, in these situations internet check is compulsory.
There are some ways to check internet availability using C# from code behind. All such ways are explained here including their limitations.
InternetGetConnectedState(wininet)
The 'wininet' API can be used to check the local system has active internet connection or not. The namespace used for this is 'System.Runtime.InteropServices' and import the dll 'wininet.dll' using DllImport. After this create a boolean variable with extern static with a function name InternetGetConnectedState with two parameters description and reservedValue as shown in example.
Note: The extern modifier is used to declare a method that is implemented externally. A common use of the extern modifier is with the DllImport attribute when you are using Interop services to call into unmanaged code. In this case, the method must also be declared as static.
Next create a method with name 'IsInternetAvailable' as boolean. The
above function will be used in this method which returns internet
status of local system
[DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int description, int reservedValue);
public static bool IsInternetAvailable()
{
try
{
int description;
return InternetGetConnectedState(out description, 0);
}
catch (Exception ex)
{
return false;
}
}
GetIsNetworkAvailable
The following example uses the GetIsNetworkAvailable method to determine if a network connection is available.
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
System.Windows.MessageBox.Show("This computer is connected to the internet");
}
else
{
System.Windows.MessageBox.Show("This computer is not connected to the internet");
}
Remarks (As per MSDN): A network connection is considered to be available if any network interface is marked "up" and is not a loopback or tunnel interface.
There are many cases in which a device or computer is not connected to a useful network but is still considered available and GetIsNetworkAvailable will return true. For example, if the device running the application is connected to a wireless network that requires a proxy, but the proxy is not set, GetIsNetworkAvailable will return true. Another example of when GetIsNetworkAvailable will return true is if the application is running on a computer that is connected to a hub or router where the hub or router has lost the upstream connection.
Ping a hostname on the network
Ping and PingReply classes allows an application to determine whether a remote computer is accessible over the network by getting reply from the host. These classes are available in System.Net.NetworkInformation namespace. The following example shows how to ping a host.
protected bool CheckConnectivity(string ipAddress)
{
bool connectionExists = false;
try
{
System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingOptions options = new System.Net.NetworkInformation.PingOptions();
options.DontFragment = true;
if (!string.IsNullOrEmpty(ipAddress))
{
System.Net.NetworkInformation.PingReply reply = pingSender.Send(ipAddress);
connectionExists = reply.Status ==
System.Net.NetworkInformation.IPStatus.Success ? true : false;
}
}
catch (PingException ex)
{
Logger.LogException(ex.Message, ex);
}
return connectionExists;
}
Remarks (As per MSDN): Applications use the Ping class to detect whether a remote computer is reachable. Network topology can determine whether Ping can successfully contact a remote host. The presence and configuration of proxies, network address translation (NAT) equipment, or firewalls can prevent Ping from succeeding. A successful Ping indicates only that the remote host can be reached on the network; the presence of higher level services (such as a Web server) on the remote host is not guaranteed.
Comments/Suggestions are invited. Happy coding......!
The accepted answer succeeds quickly but is very slow to fail when there is no connection. So I wanted to build a robust connection check that would fail faster.
Pinging was said to not be supported in all environments, so I started with the accepted answer and added a WebClient from here with a custom timeout. You can pick any timeout, but 3 seconds worked for me while connected via wifi. I tried adding a fast iteration (1 second), then a slow iteration (3 seconds) if the first one fails. But that made no sense since both iterations would always fail (when not connected) or always succeed (when connected).
I'm connecting to AWS since I want to upload a file when the connection test passes.
public static class AwsHelpers
{
public static bool GetCanConnectToAws()
{
try
{
using (var client = new WebClientWithShortTimeout())
using (client.OpenRead("https://aws.amazon.com"))
return true;
}
catch
{
return false;
}
}
}
public class WebClientWithShortTimeout: WebClient
{
protected override WebRequest GetWebRequest(Uri uri)
{
var webRequest = base.GetWebRequest(uri);
webRequest.Timeout = 5000;
return webRequest;
}
}
If you want to notify the user/take action whenever a network/connection change occur.
Use NLM API:
https://msdn.microsoft.com/en-us/library/ee264321.aspx
http://www.codeproject.com/Articles/34650/How-to-use-the-Windows-NLM-API-to-get-notified-of
public static bool Isconnected = false;
public static bool CheckForInternetConnection()
{
try
{
Ping myPing = new Ping();
String host = "google.com";
byte[] buffer = new byte[32];
int timeout = 1000;
PingOptions pingOptions = new PingOptions();
PingReply reply = myPing.Send(host, timeout, buffer, pingOptions);
if (reply.Status == IPStatus.Success)
{
return true;
}
else if (reply.Status == IPStatus.TimedOut)
{
return Isconnected;
}
else
{
return false;
}
}
catch (Exception)
{
return false;
}
}
public static void CheckConnection()
{
if (CheckForInternetConnection())
{
Isconnected = true;
}
else
{
Isconnected = false;
}
}
bool bb = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
if (bb == true)
MessageBox.Show("Internet connections are available");
else
MessageBox.Show("Internet connections are not available");
Multi threaded version of ping:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Threading;
namespace OnlineCheck
{
class Program
{
static bool isOnline = false;
static void Main(string[] args)
{
List<string> ipList = new List<string> {
"1.1.1.1", // Bad ip
"2.2.2.2",
"4.2.2.2",
"8.8.8.8",
"9.9.9.9",
"208.67.222.222",
"139.130.4.5"
};
int timeOut = 1000 * 5; // Seconds
List<Thread> threadList = new List<Thread>();
foreach (string ip in ipList)
{
Thread threadTest = new Thread(() => IsOnline(ip));
threadList.Add(threadTest);
threadTest.Start();
}
Stopwatch stopwatch = Stopwatch.StartNew();
while (!isOnline && stopwatch.ElapsedMilliseconds <= timeOut)
{
Thread.Sleep(10); // Cooldown the CPU
}
foreach (Thread thread in threadList)
{
thread.Abort(); // We love threads, don't we?
}
Console.WriteLine("Am I online: " + isOnline.ToYesNo());
Console.ReadKey();
}
static bool Ping(string host, int timeout = 3000, int buffer = 32)
{
bool result = false;
try
{
Ping ping = new Ping();
byte[] byteBuffer = new byte[buffer];
PingOptions options = new PingOptions();
PingReply reply = ping.Send(host, timeout, byteBuffer, options);
result = (reply.Status == IPStatus.Success);
}
catch (Exception ex)
{
}
return result;
}
static void IsOnline(string host)
{
isOnline = Ping(host) || isOnline;
}
}
public static class BooleanExtensions
{
public static string ToYesNo(this bool value)
{
return value ? "Yes" : "No";
}
}
}
Building on #ChaosPandion's answer, to be as sure as possible that the result is correct you can include multiple big sites like others have pointed out. However this should be done asynchronously to avoid too long wait times. Also the WebRequest, HttpWebRequest and HttpWebResponse classes are now obsolete and should be replaced by HttpClient. The following example takes into account the above:
public static async Task<bool> CheckForInternetConnection(TimeSpan? timeoutMs = null, List<string> urls = null)
{
if (timeoutMs == null)
{
timeoutMs = TimeSpan.FromSeconds(10);
}
var culture = CultureInfo.InstalledUICulture;
if (urls == null)
{
urls = new List<string>();
if (culture.Name.StartsWith("fa")) // Iran
urls.Add("http://www.aparat.com");
else if (culture.Name.StartsWith("zh")) // China
urls.Add("http://www.baidu.com");
else
{
urls.Add("https://www.apple.com/");
urls.Add("https://www.gstatic.com/generate_204");
}
}
var client = new HttpClient();
client.Timeout = (TimeSpan)timeoutMs;
List<Task<string>> tasks = new List<Task<string>>();
int unresponsiveUrlCount = 0;
foreach (var url in urls)
{
tasks.Add(client.GetStringAsync(url));
}
Task aggregationTask = null;
try
{
aggregationTask = Task.WhenAll(tasks);
await aggregationTask;
}
catch (Exception)
{
if (aggregationTask?.Exception?.InnerExceptions != null && aggregationTask.Exception.InnerExceptions.Any())
{
foreach (var innerEx in aggregationTask.Exception.InnerExceptions)
{
unresponsiveUrlCount++;
}
}
}
return unresponsiveUrlCount < urls.Count;
}
This method checks all the urls in the list and if they are all inaccessible then it returns false. I have added apple's url, because in my case it loads pretty fast, but it can be replaced with any url.
Use NetworkMonitor to monitoring network state and internet connection.
Sample:
namespace AmRoNetworkMonitor.Demo
{
using System;
internal class Program
{
private static void Main()
{
NetworkMonitor.StateChanged += NetworkMonitor_StateChanged;
NetworkMonitor.StartMonitor();
Console.WriteLine("Press any key to stop monitoring.");
Console.ReadKey();
NetworkMonitor.StopMonitor();
Console.WriteLine("Press any key to close program.");
Console.ReadKey();
}
private static void NetworkMonitor_StateChanged(object sender, StateChangeEventArgs e)
{
Console.WriteLine(e.IsAvailable ? "Is Available" : "Is Not Available");
}
}
}
For my application we also test by download tiny file.
string remoteUri = "https://www.microsoft.com/favicon.ico"
WebClient myWebClient = new WebClient();
try
{
byte[] myDataBuffer = myWebClient.DownloadData (remoteUri);
if(myDataBuffer.length > 0) // Or add more validate. eg. checksum
{
return true;
}
}
catch
{
return false;
}
Also. Some ISP may use middle server to cache file. Add random unused parameter eg. https://www.microsoft.com/favicon.ico?req=random_number
Can prevent caching.
I am having issue on those method on my 3g Router/modem, because if internet is disconnected the router redirects the page to its response page, so you still get a steam and your code think there is internet.
Apples (or others) have a hot-spot-dedection page which always returns a certain response. The following sample returns "Success" response. So you will be exactly sure you could connect the internet and get real response !
public static bool CheckForInternetConnection()
{
try
{
using (var webClient = new WebClient())
using (var stream = webClient.OpenRead("http://captive.apple.com/hotspot-detect.html"))
{
if (stream != null)
{
//return true;
stream.ReadTimeout = 1000;
using (var reader = new StreamReader(stream, Encoding.UTF8, false))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (line == "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>")
{
return true;
}
Console.WriteLine(line);
}
}
}
return false;
}
}
catch
{
}
return false;
}
I have three tests for an Internet connection.
Reference System.Net and System.Net.Sockets
Add the following test functions:
Test 1
public bool IsOnlineTest1()
{
try
{
IPHostEntry dummy = Dns.GetHostEntry("https://www.google.com");
return true;
}
catch (SocketException ex)
{
return false;
}
}
Test 2
public bool IsOnlineTest2()
{
try
{
IPHostEntry dummy = Dns.GetHostEntry("https://www.google.com");
return true;
}
catch (SocketException ex)
{
return false;
}
}
Test 3
public bool IsOnlineTest3()
{
System.Net.WebRequest req = System.Net.WebRequest.Create("https://www.google.com");
System.Net.WebResponse resp = default(System.Net.WebResponse);
try
{
resp = req.GetResponse();
resp.Close();
req = null;
return true;
}
catch (Exception ex)
{
req = null;
return false;
}
}
Performing the tests
If you make a Dictionary of String and Boolean called CheckList, you can add the results of each test to CheckList.
Now, recurse through each KeyValuePair using a for...each loop.
If CheckList contains a Value of true, then you know there is an Internet connection.
public static bool HasConnection()
{
try
{
System.Net.IPHostEntry i = System.Net.Dns.GetHostEntry("www.google.com");
return true;
}
catch
{
return false;
}
}
That works
I have a Modbus TCP/IP to MODBUS RTU converter , which comes with a default IP of 192.168.0.1 . I need to develop a small c# Winform app to change this device's IP address to any desired IP address. How do I do that?.
You could do it with WMI (Windows Management Instrumentation).
First, you have to add the reference for System.Management to your Project.
Second, you need to find the NetworkInterface for your network connection by name:
using System.Net.NetworkInformation;
using System.Management;
public class NetworkManager
{
public static NetworkInterface GetNetworkInterface(string sName)
{
NetworkInterface NetInterface = null;
// Precondition
if (sName == "") return null;
NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface ni in interfaces)
{
if (ni.Name == sName)
{
NetInterface = ni;
break;
}
}
return NetInterface;
}
Third, you have to create a ManagementObject for your NetworkInterface:
public static ManagementObject GetNetworkAdapterManagementObject(NetworkInterface NetInterface)
{
ManagementObject oMngObj = null;
// Precondition
if (NetInterface == null) return null;
string sNI = NetInterface.Id;
ManagementClass oMC = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection oMOC = oMC.GetInstances();
foreach (ManagementObject oMO in oMOC)
{
string sMO = oMO["SettingID"].ToString();
if (sMO == sNI)
{
// Found
oMngObj = oMO;
break;
}
}
return oMngObj;
}
Fours, you can set the ipadress with:
public static bool SetIPAdress(ManagementObject oMO, string[] saIPAdress, string[] saSubnetMask)
{
bool bErg = false;
try
{
// Precondition
if (oMO == null) return false;
if (saIPAdress == null) return false;
if (saSubnetMask == null) return false;
// Get ManagementBaseObject
ManagementBaseObject oNewIP = null;
oNewIP = oMO.GetMethodParameters("EnableStatic");
oNewIP["IPAddress"] = saIPAdress;
oNewIP["SubnetMask"] = saSubnetMask;
// Invoke
oMO.InvokeMethod("EnableStatic", oNewIP, null);
// Alles ok
bErg = true;
}
catch (Exception ex)
{
Console.WriteLine("SetIPAdress failed: " + ex.Message);
}
return bErg;
}
}
Now you can use it, for example in a button click event handler:
private void button1_Click(object sender, EventArgs e)
{
string sConn = "LAN-Verbindung";
NetworkInterface oNI = NetworkManager.GetNetworkInterface(sConn);
ManagementObject oMO = NetworkManager.GetNetworkAdapterManagementObject(oNI);
string sIPAdress = "192.168.1.1";
string sSubnetMask = "255.255.255.0";
string[] saIPAdress = {sIPAdress};
string[] saSubnetMask = {sSubnetMask};
if (NetworkManager.SetIPAdress(oMO, saIPAdress, saSubnetMask))
{
Console.WriteLine("Yes...");
}
}
Depending on the policies on your pc, may be you have to run the program as Administrator...
What is the fastest and most efficient way to check for Internet connectivity in .NET?
You could use this code, which should also work in Iran and China-
public static bool CheckForInternetConnection(int timeoutMs = 10000, string url = null)
{
try
{
url ??= CultureInfo.InstalledUICulture switch
{
{ Name: var n } when n.StartsWith("fa") => // Iran
"http://www.aparat.com",
{ Name: var n } when n.StartsWith("zh") => // China
"http://www.baidu.com",
_ =>
"http://www.gstatic.com/generate_204",
};
var request = (HttpWebRequest)WebRequest.Create(url);
request.KeepAlive = false;
request.Timeout = timeoutMs;
using (var response = (HttpWebResponse)request.GetResponse())
return true;
}
catch
{
return false;
}
}
There is absolutely no way you can reliably check if there is an internet connection or not (I assume you mean access to the internet).
You can, however, request resources that are virtually never offline, like pinging google.com or something similar. I think this would be efficient.
try {
Ping myPing = new Ping();
String host = "google.com";
byte[] buffer = new byte[32];
int timeout = 1000;
PingOptions pingOptions = new PingOptions();
PingReply reply = myPing.Send(host, timeout, buffer, pingOptions);
return (reply.Status == IPStatus.Success);
}
catch (Exception) {
return false;
}
Instead of checking, just perform the action (web request, mail, ftp, etc.) and be prepared for the request to fail, which you have to do anyway, even if your check was successful.
Consider the following:
1 - check, and it is OK
2 - start to perform action
3 - network goes down
4 - action fails
5 - lot of good your check did
If the network is down your action will fail just as rapidly as a ping, etc.
1 - start to perform action
2 - if the net is down(or goes down) the action will fail
NetworkInterface.GetIsNetworkAvailable is very unreliable. Just have some VMware or other LAN connection and it will return wrong result.
Also about Dns.GetHostEntry method I were just concerned about whether test URL might be blocked in the environment where my application going to deploy.
So another way I found out is using InternetGetConnectedState method.
My code is
[System.Runtime.InteropServices.DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int Description, int ReservedValue);
public static bool CheckNet()
{
int desc;
return InternetGetConnectedState(out desc, 0);
}
Pinging google.com introduces a DNS resolution dependency. Pinging 8.8.8.8 is fine but Google is several hops away from me. All I need to do is to ping the nearest thing to me that is on the internet.
I can use Ping's TTL feature to ping hop #1, then hop #2, etc, until I get a reply from something that is on a routable address; if that node is on a routable address then it is on the internet. For most of us, hop #1 will be our local gateway/router, and hop #2 will be the first point on the other side of our fibre connection or whatever.
This code works for me, and responds quicker than some of the other suggestions in this thread because it is pinging whatever is nearest to me on the internet.
using System.Diagnostics;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Tasks;
public static async Task<bool> IsConnectedToInternetAsync()
{
const int maxHops = 30;
const string someFarAwayIpAddress = "8.8.8.8";
// Keep pinging further along the line from here to google
// until we find a response that is from a routable address
for (int ttl = 1; ttl <= maxHops; ttl++)
{
var options = new PingOptions(ttl, true);
byte[] buffer = new byte[32];
PingReply reply;
try
{
using (var pinger = new Ping())
{
reply = await pinger.SendPingAsync(someFarAwayIpAddress, 10000, buffer, options);
}
}
catch (PingException pingex)
{
Debug.Print($"Ping exception (probably due to no network connection or recent change in network conditions), hence not connected to internet. Message: {pingex.Message}");
return false;
}
string address = reply.Address?.ToString() ?? null;
Debug.Print($"Hop #{ttl} is {address}, {reply.Status}");
if (reply.Status != IPStatus.TtlExpired && reply.Status != IPStatus.Success)
{
Debug.Print($"Hop #{ttl} is {reply.Status}, hence we are not connected.");
return false;
}
if (IsRoutableAddress(reply.Address))
{
Debug.Print("That's routable, so we must be connected to the internet.");
return true;
}
}
return false;
}
private static bool IsRoutableAddress(IPAddress addr)
{
if (addr == null)
{
return false;
}
else if (addr.AddressFamily == AddressFamily.InterNetworkV6)
{
return !addr.IsIPv6LinkLocal && !addr.IsIPv6SiteLocal;
}
else // IPv4
{
byte[] bytes = addr.GetAddressBytes();
if (bytes[0] == 10)
{ // Class A network
return false;
}
else if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] <= 31)
{ // Class B network
return false;
}
else if (bytes[0] == 192 && bytes[1] == 168)
{ // Class C network
return false;
}
else
{ // None of the above, so must be routable
return true;
}
}
}
A test for internet connection by pinging Google:
new Ping().Send("www.google.com.mx").Status == IPStatus.Success
I disagree with people who are stating: "What's the point in checking for connectivity before performing a task, as immediately after the check the connection may be lost".
Surely there is a degree of uncertainty in many programming tasks we as developers undertake, but reducing the uncertainty to a level of acceptance is part of the challenge.
I recently ran into this problem making an application which including a mapping feature which linked to an on-line tile server. This functionality was to be disabled where a lack of internet connectivity was noted.
Some of the responses on this page were very good, but did however cause a lot of performance issues such as hanging, mainly in the case of the absence of connectivity.
Here is the solution that I ended up using, with the help of some of these answers and my colleagues:
// Insert this where check is required, in my case program start
ThreadPool.QueueUserWorkItem(CheckInternetConnectivity);
}
void CheckInternetConnectivity(object state)
{
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
using (WebClient webClient = new WebClient())
{
webClient.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache);
webClient.Proxy = null;
webClient.OpenReadCompleted += webClient_OpenReadCompleted;
webClient.OpenReadAsync(new Uri("<url of choice here>"));
}
}
}
volatile bool internetAvailable = false; // boolean used elsewhere in code
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
internetAvailable = true;
Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
// UI changes made here
}));
}
}
I have seen all the options listed above and the only viable option to check wither the internet is available or not is the "Ping" option.
Importing [DllImport("Wininet.dll")] and System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces() Or any other variation of the NetworkInterface class does not work well in detecting the availability of the network.These Methods only check if the network cable is plugged in or not.
The "Ping option"
if(Connection is available) returns true
if(Connection is not available and the network cable is plugged in) returns false
if(Network cable is not plugged in) Throws an exception
The NetworkInterface
if(Internet Is available)Returns True
if(Internet is not Available and Network Cable is Plugged in ) Returns True
if(Network Cable is Not Plugged in )returns false
The [DllImport("Wininet.dll")]
if(Internet Is available)Returns True
if(Internet is not Available and Network Cable is Plugged in ) Returns True
if(Network Cable is Not Plugged in )returns false
So in case of [DllImport("Wininet.dll")] and NetworkInterface There is no way of knowing if internet connection is available.
Does not solve the problem of network going down between checking and running your code
but is fairly reliable
public static bool IsAvailableNetworkActive()
{
// only recognizes changes related to Internet adapters
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
// however, this will include all adapters -- filter by opstatus and activity
NetworkInterface[] interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
return (from face in interfaces
where face.OperationalStatus == OperationalStatus.Up
where (face.NetworkInterfaceType != NetworkInterfaceType.Tunnel) && (face.NetworkInterfaceType != NetworkInterfaceType.Loopback)
select face.GetIPv4Statistics()).Any(statistics => (statistics.BytesReceived > 0) && (statistics.BytesSent > 0));
}
return false;
}
Here's how it is implemented in Android.
As a proof of concept, I translated this code to C#:
var request = (HttpWebRequest)WebRequest.Create("http://g.cn/generate_204");
request.UserAgent = "Android";
request.KeepAlive = false;
request.Timeout = 1500;
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.ContentLength == 0 && response.StatusCode == HttpStatusCode.NoContent)
{
//Connection to internet available
}
else
{
//Connection to internet not available
}
}
private bool ping()
{
System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingReply reply = pingSender.Send(address);
if (reply.Status == System.Net.NetworkInformation.IPStatus.Success)
{
return true;
}
else
{
return false;
}
}
Try to avoid testing connections by catching the exception. because we really Expect that sometimes we may lose network connection.
if (NetworkInterface.GetIsNetworkAvailable() &&
new Ping().Send(new IPAddress(new byte[] { 8, 8, 8, 8 }),2000).Status == IPStatus.Success)
//is online
else
//is offline
I wouldn't think it's impossible, just not straightforward.
I've built something like this, and yes it's not perfect, but the first step is essential: to check if there's any network connectivity. The Windows Api doesn't do a great job, so why not do a better job?
bool NetworkIsAvailable()
{
var all = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
foreach (var item in all)
{
if (item.NetworkInterfaceType == NetworkInterfaceType.Loopback)
continue;
if (item.Name.ToLower().Contains("virtual") || item.Description.ToLower().Contains("virtual"))
continue; //Exclude virtual networks set up by VMWare and others
if (item.OperationalStatus == OperationalStatus.Up)
{
return true;
}
}
return false;
}
It's pretty simple, but it really helps improve the quality of the check, especially when you want to check various proxy configurations.
So:
Check whether there's network connectivity (make this really good, maybe even have logs sent back to developers when there are false positives to improve the NetworkIsAvailable function)
HTTP Ping
(Cycle through Proxy configurations with HTTP Pings on each)
Another option is the Network List Manager API which is available for Vista and Windows 7. MSDN article here. In the article is a link to download code samples which allow you to do this:
AppNetworkListUser nlmUser = new AppNetworkListUser();
Console.WriteLine("Is the machine connected to internet? " + nlmUser.NLM.IsConnectedToInternet.ToString());
Be sure to add a reference to Network List 1.0 Type Library from the COM tab... which will show up as NETWORKLIST.
I personally find the answer of Anton and moffeltje best, but I added a check to exclude virtual networks set up by VMWare and others.
public static bool IsAvailableNetworkActive()
{
// only recognizes changes related to Internet adapters
if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()) return false;
// however, this will include all adapters -- filter by opstatus and activity
NetworkInterface[] interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
return (from face in interfaces
where face.OperationalStatus == OperationalStatus.Up
where (face.NetworkInterfaceType != NetworkInterfaceType.Tunnel) && (face.NetworkInterfaceType != NetworkInterfaceType.Loopback)
where (!(face.Name.ToLower().Contains("virtual") || face.Description.ToLower().Contains("virtual")))
select face.GetIPv4Statistics()).Any(statistics => (statistics.BytesReceived > 0) && (statistics.BytesSent > 0));
}
Introduction
In some scenarios you need to check whether internet is available or not using C# code in windows applications. May be to download or upload a file using internet in windows forms or to get some data from database which is at remote location, in these situations internet check is compulsory.
There are some ways to check internet availability using C# from code behind. All such ways are explained here including their limitations.
InternetGetConnectedState(wininet)
The 'wininet' API can be used to check the local system has active internet connection or not. The namespace used for this is 'System.Runtime.InteropServices' and import the dll 'wininet.dll' using DllImport. After this create a boolean variable with extern static with a function name InternetGetConnectedState with two parameters description and reservedValue as shown in example.
Note: The extern modifier is used to declare a method that is implemented externally. A common use of the extern modifier is with the DllImport attribute when you are using Interop services to call into unmanaged code. In this case, the method must also be declared as static.
Next create a method with name 'IsInternetAvailable' as boolean. The
above function will be used in this method which returns internet
status of local system
[DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int description, int reservedValue);
public static bool IsInternetAvailable()
{
try
{
int description;
return InternetGetConnectedState(out description, 0);
}
catch (Exception ex)
{
return false;
}
}
GetIsNetworkAvailable
The following example uses the GetIsNetworkAvailable method to determine if a network connection is available.
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
System.Windows.MessageBox.Show("This computer is connected to the internet");
}
else
{
System.Windows.MessageBox.Show("This computer is not connected to the internet");
}
Remarks (As per MSDN): A network connection is considered to be available if any network interface is marked "up" and is not a loopback or tunnel interface.
There are many cases in which a device or computer is not connected to a useful network but is still considered available and GetIsNetworkAvailable will return true. For example, if the device running the application is connected to a wireless network that requires a proxy, but the proxy is not set, GetIsNetworkAvailable will return true. Another example of when GetIsNetworkAvailable will return true is if the application is running on a computer that is connected to a hub or router where the hub or router has lost the upstream connection.
Ping a hostname on the network
Ping and PingReply classes allows an application to determine whether a remote computer is accessible over the network by getting reply from the host. These classes are available in System.Net.NetworkInformation namespace. The following example shows how to ping a host.
protected bool CheckConnectivity(string ipAddress)
{
bool connectionExists = false;
try
{
System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingOptions options = new System.Net.NetworkInformation.PingOptions();
options.DontFragment = true;
if (!string.IsNullOrEmpty(ipAddress))
{
System.Net.NetworkInformation.PingReply reply = pingSender.Send(ipAddress);
connectionExists = reply.Status ==
System.Net.NetworkInformation.IPStatus.Success ? true : false;
}
}
catch (PingException ex)
{
Logger.LogException(ex.Message, ex);
}
return connectionExists;
}
Remarks (As per MSDN): Applications use the Ping class to detect whether a remote computer is reachable. Network topology can determine whether Ping can successfully contact a remote host. The presence and configuration of proxies, network address translation (NAT) equipment, or firewalls can prevent Ping from succeeding. A successful Ping indicates only that the remote host can be reached on the network; the presence of higher level services (such as a Web server) on the remote host is not guaranteed.
Comments/Suggestions are invited. Happy coding......!
The accepted answer succeeds quickly but is very slow to fail when there is no connection. So I wanted to build a robust connection check that would fail faster.
Pinging was said to not be supported in all environments, so I started with the accepted answer and added a WebClient from here with a custom timeout. You can pick any timeout, but 3 seconds worked for me while connected via wifi. I tried adding a fast iteration (1 second), then a slow iteration (3 seconds) if the first one fails. But that made no sense since both iterations would always fail (when not connected) or always succeed (when connected).
I'm connecting to AWS since I want to upload a file when the connection test passes.
public static class AwsHelpers
{
public static bool GetCanConnectToAws()
{
try
{
using (var client = new WebClientWithShortTimeout())
using (client.OpenRead("https://aws.amazon.com"))
return true;
}
catch
{
return false;
}
}
}
public class WebClientWithShortTimeout: WebClient
{
protected override WebRequest GetWebRequest(Uri uri)
{
var webRequest = base.GetWebRequest(uri);
webRequest.Timeout = 5000;
return webRequest;
}
}
If you want to notify the user/take action whenever a network/connection change occur.
Use NLM API:
https://msdn.microsoft.com/en-us/library/ee264321.aspx
http://www.codeproject.com/Articles/34650/How-to-use-the-Windows-NLM-API-to-get-notified-of
public static bool Isconnected = false;
public static bool CheckForInternetConnection()
{
try
{
Ping myPing = new Ping();
String host = "google.com";
byte[] buffer = new byte[32];
int timeout = 1000;
PingOptions pingOptions = new PingOptions();
PingReply reply = myPing.Send(host, timeout, buffer, pingOptions);
if (reply.Status == IPStatus.Success)
{
return true;
}
else if (reply.Status == IPStatus.TimedOut)
{
return Isconnected;
}
else
{
return false;
}
}
catch (Exception)
{
return false;
}
}
public static void CheckConnection()
{
if (CheckForInternetConnection())
{
Isconnected = true;
}
else
{
Isconnected = false;
}
}
bool bb = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
if (bb == true)
MessageBox.Show("Internet connections are available");
else
MessageBox.Show("Internet connections are not available");
Multi threaded version of ping:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Threading;
namespace OnlineCheck
{
class Program
{
static bool isOnline = false;
static void Main(string[] args)
{
List<string> ipList = new List<string> {
"1.1.1.1", // Bad ip
"2.2.2.2",
"4.2.2.2",
"8.8.8.8",
"9.9.9.9",
"208.67.222.222",
"139.130.4.5"
};
int timeOut = 1000 * 5; // Seconds
List<Thread> threadList = new List<Thread>();
foreach (string ip in ipList)
{
Thread threadTest = new Thread(() => IsOnline(ip));
threadList.Add(threadTest);
threadTest.Start();
}
Stopwatch stopwatch = Stopwatch.StartNew();
while (!isOnline && stopwatch.ElapsedMilliseconds <= timeOut)
{
Thread.Sleep(10); // Cooldown the CPU
}
foreach (Thread thread in threadList)
{
thread.Abort(); // We love threads, don't we?
}
Console.WriteLine("Am I online: " + isOnline.ToYesNo());
Console.ReadKey();
}
static bool Ping(string host, int timeout = 3000, int buffer = 32)
{
bool result = false;
try
{
Ping ping = new Ping();
byte[] byteBuffer = new byte[buffer];
PingOptions options = new PingOptions();
PingReply reply = ping.Send(host, timeout, byteBuffer, options);
result = (reply.Status == IPStatus.Success);
}
catch (Exception ex)
{
}
return result;
}
static void IsOnline(string host)
{
isOnline = Ping(host) || isOnline;
}
}
public static class BooleanExtensions
{
public static string ToYesNo(this bool value)
{
return value ? "Yes" : "No";
}
}
}
Building on #ChaosPandion's answer, to be as sure as possible that the result is correct you can include multiple big sites like others have pointed out. However this should be done asynchronously to avoid too long wait times. Also the WebRequest, HttpWebRequest and HttpWebResponse classes are now obsolete and should be replaced by HttpClient. The following example takes into account the above:
public static async Task<bool> CheckForInternetConnection(TimeSpan? timeoutMs = null, List<string> urls = null)
{
if (timeoutMs == null)
{
timeoutMs = TimeSpan.FromSeconds(10);
}
var culture = CultureInfo.InstalledUICulture;
if (urls == null)
{
urls = new List<string>();
if (culture.Name.StartsWith("fa")) // Iran
urls.Add("http://www.aparat.com");
else if (culture.Name.StartsWith("zh")) // China
urls.Add("http://www.baidu.com");
else
{
urls.Add("https://www.apple.com/");
urls.Add("https://www.gstatic.com/generate_204");
}
}
var client = new HttpClient();
client.Timeout = (TimeSpan)timeoutMs;
List<Task<string>> tasks = new List<Task<string>>();
int unresponsiveUrlCount = 0;
foreach (var url in urls)
{
tasks.Add(client.GetStringAsync(url));
}
Task aggregationTask = null;
try
{
aggregationTask = Task.WhenAll(tasks);
await aggregationTask;
}
catch (Exception)
{
if (aggregationTask?.Exception?.InnerExceptions != null && aggregationTask.Exception.InnerExceptions.Any())
{
foreach (var innerEx in aggregationTask.Exception.InnerExceptions)
{
unresponsiveUrlCount++;
}
}
}
return unresponsiveUrlCount < urls.Count;
}
This method checks all the urls in the list and if they are all inaccessible then it returns false. I have added apple's url, because in my case it loads pretty fast, but it can be replaced with any url.
Use NetworkMonitor to monitoring network state and internet connection.
Sample:
namespace AmRoNetworkMonitor.Demo
{
using System;
internal class Program
{
private static void Main()
{
NetworkMonitor.StateChanged += NetworkMonitor_StateChanged;
NetworkMonitor.StartMonitor();
Console.WriteLine("Press any key to stop monitoring.");
Console.ReadKey();
NetworkMonitor.StopMonitor();
Console.WriteLine("Press any key to close program.");
Console.ReadKey();
}
private static void NetworkMonitor_StateChanged(object sender, StateChangeEventArgs e)
{
Console.WriteLine(e.IsAvailable ? "Is Available" : "Is Not Available");
}
}
}
For my application we also test by download tiny file.
string remoteUri = "https://www.microsoft.com/favicon.ico"
WebClient myWebClient = new WebClient();
try
{
byte[] myDataBuffer = myWebClient.DownloadData (remoteUri);
if(myDataBuffer.length > 0) // Or add more validate. eg. checksum
{
return true;
}
}
catch
{
return false;
}
Also. Some ISP may use middle server to cache file. Add random unused parameter eg. https://www.microsoft.com/favicon.ico?req=random_number
Can prevent caching.
I am having issue on those method on my 3g Router/modem, because if internet is disconnected the router redirects the page to its response page, so you still get a steam and your code think there is internet.
Apples (or others) have a hot-spot-dedection page which always returns a certain response. The following sample returns "Success" response. So you will be exactly sure you could connect the internet and get real response !
public static bool CheckForInternetConnection()
{
try
{
using (var webClient = new WebClient())
using (var stream = webClient.OpenRead("http://captive.apple.com/hotspot-detect.html"))
{
if (stream != null)
{
//return true;
stream.ReadTimeout = 1000;
using (var reader = new StreamReader(stream, Encoding.UTF8, false))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (line == "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>")
{
return true;
}
Console.WriteLine(line);
}
}
}
return false;
}
}
catch
{
}
return false;
}
I have three tests for an Internet connection.
Reference System.Net and System.Net.Sockets
Add the following test functions:
Test 1
public bool IsOnlineTest1()
{
try
{
IPHostEntry dummy = Dns.GetHostEntry("https://www.google.com");
return true;
}
catch (SocketException ex)
{
return false;
}
}
Test 2
public bool IsOnlineTest2()
{
try
{
IPHostEntry dummy = Dns.GetHostEntry("https://www.google.com");
return true;
}
catch (SocketException ex)
{
return false;
}
}
Test 3
public bool IsOnlineTest3()
{
System.Net.WebRequest req = System.Net.WebRequest.Create("https://www.google.com");
System.Net.WebResponse resp = default(System.Net.WebResponse);
try
{
resp = req.GetResponse();
resp.Close();
req = null;
return true;
}
catch (Exception ex)
{
req = null;
return false;
}
}
Performing the tests
If you make a Dictionary of String and Boolean called CheckList, you can add the results of each test to CheckList.
Now, recurse through each KeyValuePair using a for...each loop.
If CheckList contains a Value of true, then you know there is an Internet connection.
public static bool HasConnection()
{
try
{
System.Net.IPHostEntry i = System.Net.Dns.GetHostEntry("www.google.com");
return true;
}
catch
{
return false;
}
}
That works
I want to free a TCP port during startup of my application (asking confirmation to user), how to get the PID number and then, if the user confirm, kill it?
I know I can get this information by netstat, but how to do it in a script or better in a C# method.
You can run netstat then redirect the output to a text stream so you can parse and get the info you want.
Here is what i did.
Run netstat -a -n -o as a Process
redirect the standard out put and capture the output text
capture the result, parse and return all the processes in use
check if the port is being used
find the process using linq
Run Process.Kill()
you will have to do the exception handling.
namespace test
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
Console.WriteLine("Port number you want to clear");
var input = Console.ReadLine();
//var port = int.Parse(input);
var prc = new ProcManager();
prc.KillByPort(7972); //prc.KillbyPort(port);
}
}
public class PRC
{
public int PID { get; set; }
public int Port { get; set; }
public string Protocol { get; set; }
}
public class ProcManager
{
public void KillByPort(int port)
{
var processes = GetAllProcesses();
if (processes.Any(p => p.Port == port))
try{
Process.GetProcessById(processes.First(p => p.Port == port).PID).Kill();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
else
{
Console.WriteLine("No process to kill!");
}
}
public List<PRC> GetAllProcesses()
{
var pStartInfo = new ProcessStartInfo();
pStartInfo.FileName = "netstat.exe";
pStartInfo.Arguments = "-a -n -o";
pStartInfo.WindowStyle = ProcessWindowStyle.Maximized;
pStartInfo.UseShellExecute = false;
pStartInfo.RedirectStandardInput = true;
pStartInfo.RedirectStandardOutput = true;
pStartInfo.RedirectStandardError = true;
var process = new Process()
{
StartInfo = pStartInfo
};
process.Start();
var soStream = process.StandardOutput;
var output = soStream.ReadToEnd();
if(process.ExitCode != 0)
throw new Exception("somethign broke");
var result = new List<PRC>();
var lines = Regex.Split(output, "\r\n");
foreach (var line in lines)
{
if(line.Trim().StartsWith("Proto"))
continue;
var parts = line.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries);
var len = parts.Length;
if(len > 2)
result.Add(new PRC
{
Protocol = parts[0],
Port = int.Parse(parts[1].Split(':').Last()),
PID = int.Parse(parts[len - 1])
});
}
return result;
}
}
}