使用.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。
如果您想在networking/连接更改发生时通知用户/采取措施。
使用NLM API:
我个人觉得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.Net
和System.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一个名为CheckList
的String
和Boolean
的Dictionary
,您可以将每个testing的结果添加到CheckList
。
现在,使用for...each
循环遍历每个KeyValuePair
。
如果CheckList
的true
,那么你知道有一个互联网连接。
bool bb = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable(); if (bb == true) MessageBox.Show("Internet connections are available"); else MessageBox.Show("Internet connections are not available");