什么是最快,最有效的方法来检查.NET中的Internet连接?
Windows NLM API
应该是最好的。stackoverflow.com/questions/5405895/...
什么是最快,最有效的方法来检查.NET中的Internet连接?
Windows NLM API
应该是最好的。stackoverflow.com/questions/5405895/...
Answers:
这样的事情应该起作用。
public static bool CheckForInternetConnection()
{
try
{
using (var client = new WebClient())
using (client.OpenRead("http://google.com/generate_204"))
return true;
}
catch
{
return false;
}
}
I cannot image a world where www.google.com does not return some HTML
在中国为例...
绝对没有办法可靠地检查是否存在互联网连接(我假设您的意思是访问互联网)。
但是,您可以请求几乎永不脱机的资源,例如ping 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;
}
8.8.8.8
或8.8.4.4
)对我来说很好。
Beware - many schools and offices block the ping protocol.
如果您将这种方法用于将由客户端使用的应用程序,则建议不要使用这种检查Internet的方法
除了检查之外,只需执行操作(Web请求,邮件,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
如果网络中断,您的操作将像ping一样迅速失败。
1 - start to perform action
2 - if the net is down(or goes down) the action will fail
NetworkInterface.GetIsNetworkAvailable
是非常不可靠的 仅具有某些VMware或其他LAN连接,它将返回错误的结果。此外,关于Dns.GetHostEntry
方法,我只是担心测试URL是否在要部署应用程序的环境中被阻止。
所以我发现的另一种方法是使用InternetGetConnectedState
method。我的代码是
[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);
}
通过对Google进行ping操作来测试互联网连接:
new Ping().Send("www.google.com.mx").Status == IPStatus.Success
我不同意那些发表声明的人:“执行任务之前检查连通性有什么意义,因为检查之后可能会立即失去连接”。作为开发人员,我们在许多编程任务中肯定存在一定程度的不确定性,但是将不确定性降低到可接受的水平是挑战的一部分。
我最近在制作一个应用程序时遇到了这个问题,该应用程序包含一个链接到在线图块服务器的映射功能。如果发现缺乏互联网连接,则应禁用此功能。
此页面上的某些响应非常好,但是确实引起了很多性能问题,例如挂起,主要是在没有连接的情况下。
在其中一些答案和我的同事的帮助下,这是我最终使用的解决方案:
// 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
}));
}
}
我已经看到了上面列出的所有选项,并且唯一可以用来检查互联网是否可用的可行选项是“ Ping”选项。导入 [DllImport("Wininet.dll")]
和/ System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
或其他任何NetworkInterface
类的变体 在检测网络的可用性方面效果不佳。这些方法仅检查网络电缆是否已插入。
“ Ping选项”
if
(连接可用)返回 true
if
(连接不可用,并且网络电缆已插入)返回 false
if
(未插入网络电缆) Throws an exception
网络接口
if
(可以使用互联网)返回 True
if
(Internet不可用,并且网络电缆已插入)返回 True
if
(未插入网络电缆)返回 false
[DllImport(“ Wininet.dll”)]
if
(可以使用互联网)返回 True
if
(Internet不可用,并且网络电缆已插入)返回 True
if
(未插入网络电缆)返回 false
所以在的情况下,[DllImport("Wininet.dll")]
并 NetworkInterface
没有知道,如果Internet连接可用的方式。
不能解决检查和运行代码之间网络中断的问题,但是相当可靠
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;
}
Ping google.com引入了DNS解析依赖性。Ping 8.8.8.8很好,但是Google离我只有几步之遥。我需要做的就是对互联网上距我最近的设备执行ping操作。
我可以使用Ping的TTL功能对第一个跃点,第二个跃点等进行ping操作,直到收到可路由地址上的内容的回复为止。如果该节点位于可路由地址上,则它位于Internet上。对于我们大多数人来说,第1跳将是我们的本地网关/路由器,而第2跳将是我们光纤连接另一端或其他任何地方的第一点。
此代码对我有用,并且比该线程中的其他一些建议更快地响应,因为它可以对Internet上最接近我的对象执行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;
}
}
}
这是在Android中实现的方式。
作为概念证明,我将此代码翻译为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;
}
}
另一种选择是网络列表管理器API,它是适用于Vista和Windows 7 MSDN文章在这里。本文中的链接是下载代码示例的链接,您可以执行以下操作:
AppNetworkListUser nlmUser = new AppNetworkListUser();
Console.WriteLine("Is the machine connected to internet? " + nlmUser.NLM.IsConnectedToInternet.ToString());
确保从“ COM”选项卡中添加对Network List 1.0 Type Library的引用...,该引用将显示为NETWORKLIST。
尝试通过捕获异常来避免测试连接。因为我们真的希望有时我们可能会失去网络连接。
if (NetworkInterface.GetIsNetworkAvailable() &&
new Ping().Send(new IPAddress(new byte[] { 8, 8, 8, 8 }),2000).Status == IPStatus.Success)
//is online
else
//is offline
如果您希望在网络/连接发生更改时通知用户/采取措施。
使用NLM API:
我个人认为Anton和moffeltje的答案是最好的,但是我添加了一项检查以排除由VMWare和其他人建立的虚拟网络。
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));
}
bool bb = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
if (bb == true)
MessageBox.Show("Internet connections are available");
else
MessageBox.Show("Internet connections are not available");
bb
即使网络未连接到Internet ,也仍然适用。
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";
}
}
}
我认为这不可能,只是不简单。
我已经构建了类似的东西,是的,它并不完美,但是第一步是必不可少的:检查是否存在任何网络连接。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;
}
这很简单,但确实有助于提高检查质量,尤其是当您要检查各种代理配置时。
所以:
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;
}
}
使用NetworkMonitor监视网络状态和Internet连接。
样品:
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");
}
}
}
介绍
在某些情况下,您需要使用Windows应用程序中的C#代码检查Internet是否可用。可能是使用Internet以Windows形式下载或上传文件,或者是从远程位置的数据库中获取一些数据,在这种情况下,必须进行Internet检查。
有一些方法可以使用C#从后面的代码检查Internet可用性。此处说明所有这些方式,包括其局限性。
“ wininet” API可用于检查本地系统是否具有有效的Internet连接。用于此的名称空间是“ System.Runtime.InteropServices”,并使用DllImport导入dll“ wininet.dll”。之后,创建一个带有extern static的布尔变量,其函数名称为InternetGetConnectedState,带有两个参数description和reservedValue,如示例所示。
注意:extern修饰符用于声明在外部实现的方法。当您使用Interop服务调用非托管代码时,extern修饰符通常与DllImport属性一起使用。在这种情况下,该方法还必须声明为静态。
接下来,创建一个名称为“ IsInternetAvailable”的方法作为布尔值。此函数将使用上面的函数,该函数返回本地系统的Internet状态
[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方法确定网络连接是否可用。
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");
}
备注(根据MSDN):如果任何网络接口标记为“打开”并且不是环回或隧道接口,则认为网络连接可用。
在许多情况下,设备或计算机未连接到有用的网络,但仍被认为可用,并且GetIsNetworkAvailable将返回true。例如,如果运行应用程序的设备连接到需要代理的无线网络,但未设置代理,则GetIsNetworkAvailable将返回true。GetIsNetworkAvailable将返回true的另一个示例是,如果应用程序正在连接到集线器或路由器的计算机上运行,而集线器或路由器失去了上游连接。
Ping和PingReply类允许应用程序通过获取主机的答复来确定是否可以通过网络访问远程计算机。这些类在System.Net.NetworkInformation命名空间中可用。以下示例显示如何ping主机。
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;
}
备注(根据MSDN):应用程序使用Ping类检测远程计算机是否可访问。网络拓扑可以确定Ping是否可以成功联系远程主机。代理,网络地址转换(NAT)设备或防火墙的存在和配置可以阻止Ping成功。Ping成功表示仅在网络上可以访问远程主机。不能保证远程主机上存在更高级别的服务(例如Web服务器)。
欢迎发表评论/建议。编码愉快!!
对于我的应用程序,我们还通过下载微小文件进行测试。
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可能会使用中间服务器来缓存文件。添加随机未使用的参数,例如。https://www.microsoft.com/favicon.ico?req=random_number 可以防止缓存。
我在3g路由器/调制解调器上的那些方法上遇到问题,因为如果Internet断开连接,路由器会将页面重定向到其响应页面,因此您仍然会遇到麻烦,并且您的代码认为存在互联网。苹果(或其他)具有热点检测页面,该页面始终返回一定的响应。下面的示例返回“成功”响应。因此,您将完全确定可以连接互联网并获得真实的响应!
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;
}
我有三个Internet连接测试。
System.Net
和System.Net.Sockets
测试1
public bool IsOnlineTest1()
{
try
{
IPHostEntry dummy = Dns.GetHostEntry("https://www.google.com");
return true;
}
catch (SocketException ex)
{
return false;
}
}
测试2
public bool IsOnlineTest2()
{
try
{
IPHostEntry dummy = Dns.GetHostEntry("https://www.google.com");
return true;
}
catch (SocketException ex)
{
return false;
}
}
测试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;
}
}
执行测试
如果你做出Dictionary
的String
,并Boolean
呼吁CheckList
,在每次测试的结果添加到CheckList
。
现在,KeyValuePair
使用for...each
循环递归遍历每个对象。
如果CheckList
包含Value
的true
,则说明存在Internet连接。
public static bool HasConnection()
{
try
{
System.Net.IPHostEntry i = System.Net.Dns.GetHostEntry("www.google.com");
return true;
}
catch
{
return false;
}
}
这样可行