What is the fastest and most efficient way to check for Internet connectivity in .NET?
问题:
回答1:
Something like this should work.
System.Net.WebClient
public static bool CheckForInternetConnection()
{
try
{
using (var client = new WebClient())
using (client.OpenRead(\"http://clients3.google.com/generate_204\"))
{
return true;
}
}
catch
{
return false;
}
}
回答2:
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;
}
回答3:
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
回答4:
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);
}
回答5:
A test for internet connection by pinging Google:
new Ping().Send(\"www.google.com.mx\").Status == IPStatus.Success
回答6:
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
}));
}
}
回答7:
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;
}
回答8:
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.
回答9:
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;
}
}
回答10:
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.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Diagnostics;
internal static bool ConnectedToInternet()
{
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++)
{
Ping pinger = new Ping();
PingOptions options = new PingOptions(ttl, true);
byte[] buffer = new byte[32];
PingReply reply = null;
try
{
reply = pinger.Send(someFarAwayIpAddress, 10000, buffer, options);
}
catch (System.Net.NetworkInformation.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;
}
System.Diagnostics.Debug.Print(\"Hop #\" + ttl.ToString() + \" is \" + (reply.Address == null ? \"null\" : reply.Address.ToString()) + \", \" + reply.Status.ToString());
if (reply.Status != IPStatus.TtlExpired && reply.Status != IPStatus.Success)
{
Debug.Print(\"Hop #\" + ttl.ToString() + \" is \" + reply.Status.ToString() + \", hence we are not connected.\");
return false;
}
if (IsRoutableAddress(reply.Address))
{
System.Diagnostics.Debug.Print(\"That\'s routable so you 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;
}
}
}
回答11:
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
}
}
回答12:
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.
回答13:
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));
}
回答14:
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
回答15:
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)
回答16:
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;
}
}
回答17:
bool bb = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
if (bb == true)
MessageBox.Show(\"Internet connections are available\");
else
MessageBox.Show(\"Internet connections are not available\");
回答18:
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\";
}
}
}
回答19:
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\");
}
}
}
回答20:
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.
回答21:
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;
}
回答22:
I have three tests for an Internet connection.
- Reference
System.Net
andSystem.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.
回答23:
public static bool HasConnection()
{
try
{
System.Net.IPHostEntry i = System.Net.Dns.GetHostEntry(\"www.google.com\");
return true;
}
catch
{
return false;
}
}
That works