使用.NET检查Internet连接的最佳方法是什么?

在.NET中检查Internet连接的最快和最有效的方法是什么?

像这样的东西应该工作。

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; } } 

绝对没有办法可以可靠地检查是否有互联网连接(我假设你的意思是访问互联网)。

但是,您可以请求几乎不会脱机的资源,例如Pinging google.com或类似的东西。 我认为这将是有效的。

 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; } 

而不是检查,只是执行操作(networking请求,邮件,FTP等),并准备要求失败,即使您的支票成功,您仍然必须做。

考虑以下几点:

 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 

如果networking出现故障,您的操作将会像ping一样快

 1 - start to perform action 2 - if the net is down(or goes down) the action will fail 

NetworkInterface.GetIsNetworkAvailable是非常不可靠的。 只是有一些VMware或其他局域网连接,它会返回错误的结果。 另外关于Dns.GetHostEntry方法,我只关心testingURL是否可能在我的应用程序要部署的环境中被阻塞。

所以我发现另一种方法是使用InternetGetConnectedState方法。 我的代码是

 [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); } 

ping Google的互联网连接testing:

 new Ping().Send("www.google.com.mx").Status == IPStatus.Success 

我不同意这样的观点:“在执行任务之前检查连通性的重点是什么?在检查连接可能会丢失后立即进行检查”。 在开发者所承担的许多编程任务中,确实存在一定程度的不确定性,但将不确定性降低到接受水平是其中的一部分。

我最近遇到了这个问题,使一个应用程序,其中包括一个映射function链接到一个在线瓷砖服务器。 在缺乏互联网连接的情况下,该function被禁用。

在这个页面上的一些反应非常好,但是却造成了很多性能问题,比如挂起,主要是在没有连接的情况下。

下面是我最终使用的解决scheme,在这些答案和我的同事的帮助下:

  // 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 })); } } 

没有解决检查和运行你的代码之间的networking问题,但相当可靠

 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; } 
 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; } } 

Pinging google.com引入了DNSparsing依赖关系。 Pinging 8.8.8.8没问题,但Google离我几跳。 我所要做的就是把最近的东西打到网上。

我可以使用Ping的TTL特性来跳转#1,然后跳转#2等,直到我得到来自可路由地址上的东西的回复。 如果该节点在可路由地址上,则它在互联​​网上。 对于我们大多数人来说,跳#1将是我们的本地网关/路由器,而跳#2将成为我们光纤连接另一端的第一个点。

这段代码适用于我,并且比这个线程中的一些其他build议反应更快,因为它正在ping任何离我最近的互联网。

 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; } } } 

我已经看到了上面列出的所有选项,唯一可行的选项来检查互联网是否可用是“平”选项。 导入[DllImport("Wininet.dll")]System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()或者NetworkInterface类的任何其他变体在检测networking的可用性方面效果不佳。这些方法只检查networking电缆插入或不插入。

“Ping选项”

if (连接可用)返回true

if (连接不可用并且networking电缆已插入)返回false

if (networking电缆未插入) Throws an exception

NetworkInterface

if (Internet可用)返回True

if (Internet不可用,networking电缆插入)返回True

if (网线未插入)返回false

[DllImport(“Wininet.dll”)]

if (Internet可用)返回True

if (Internet不可用,networking电缆插入)返回True

if (网线未插入)返回false

所以在[DllImport("Wininet.dll")]NetworkInterface情况下没有办法知道互联网连接是否可用。

这是如何在Android中实现的。

作为一个概念certificate,我把这个代码翻译成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 } } 

对于我的应用程序,我们也通过下载小文件来testing

 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; } 

也。 有些ISP可能使用中间服务器来caching文件。 添加随机未使用的参数,例如。 https://www.microsoft.com/favicon.ico?req=random_number可以防止caching。;

我在我的3G路由器/调制解调器上的这些方法问题,因为如果互联网断开路由器redirect页面的响应页面,所以你仍然得到蒸汽,你的代码认为有互联网。 苹果(或其他人)有一个热点,它总是返回一个特定的响应。 以下示例返回“成功”响应。 所以你会确定你可以连接互联网,并得到真正的回应!

 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; } 

另一种select是可用于Vista和Windows 7的networking列表pipe理器API。MSDN文章在这里 。 在文章中是一个链接,下载代码示例,让你这样做:

 AppNetworkListUser nlmUser = new AppNetworkListUser(); Console.WriteLine("Is the machine connected to internet? " + nlmUser.NLM.IsConnectedToInternet.ToString()); 

请务必从COM选项卡添加对networking列表1.0types库的引用…将显示为NETWORKLIST。

我个人觉得Anton和moffeltje的答案最好,但我添加了一个检查来排除VMWare和其他人build立的虚拟networking。

 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)); } 

我不认为这是不可能的,只是不直截了当。

我已经build立了这样的东西,是的,这不是完美的,但第一步是至关重要的:检查是否有任何networking连接。 Windows API并不是很好,为什么不做更好的工作呢?

 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; } 

这很简单,但它确实有助于提高支票的质量,特别是当您要检查各种代理configuration时。

所以:

  • 检查是否有networking连接(如果有误报可以改善NetworkIsAvailablefunction,则可以使这个function非常好,甚至可以将日志发送给开发人员)
  • HTTP Ping
  • (循环通过每个HTTP Pings的代理configuration)
 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; } } 
 public static bool HasConnection() { try { System.Net.IPHostEntry i = System.Net.Dns.GetHostEntry("www.google.com"); return true; } catch { return false; } } 

这样可行

我有三个互联网连接testing。

  • 参考System.NetSystem.Net.Sockets
  • 添加以下testingfunction:

testing1

 public bool IsOnlineTest1() { try { IPHostEntry dummy = Dns.GetHostEntry("https://www.google.com"); return true; } catch (SocketException ex) { return false; } } 

testing2

 public bool IsOnlineTest2() { try { IPHostEntry dummy = Dns.GetHostEntry("https://www.google.com"); return true; } catch (SocketException ex) { return false; } } 

testing3

 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; } } 

执行testing

如果您创build一个名为CheckListStringBooleanDictionary ,您可以将每个testing的结果添加到CheckList

现在,使用for...each循环遍历每个KeyValuePair

如果CheckListtrue ,那么你知道有一个互联网连接。

 bool bb = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable(); if (bb == true) MessageBox.Show("Internet connections are available"); else MessageBox.Show("Internet connections are not available");