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

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

303342 次浏览
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;
}
}

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

但是,您可以请求几乎从未离线的资源,例如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;
}
public static bool HasConnection()
{
try
{
System.Net.IPHostEntry i = System.Net.Dns.GetHostEntry("www.google.com");
return true;
}
catch
{
return false;
}
}

工作

而不是检查,只需执行操作(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

通过ping谷歌测试网络连接:

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

另一种选择是网络列表管理器API,它适用于Vista和Windows 7。MSDN文章在这里。在本文中有一个下载代码示例的链接,允许您这样做:

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

请确保从COM选项卡中添加对网络列表1.0类型库的引用…它将显示为NETWORKLIST。

bool bb = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();


if (bb == true)
MessageBox.Show("Internet connections are available");
else
MessageBox.Show("Internet connections are not available");
我不同意有人说:“在执行任务之前检查连接有什么意义,因为检查之后连接可能会丢失”。 当然,我们作为开发人员承担的许多编程任务中都存在一定程度的不确定性,但将不确定性降低到可接受的水平是挑战的一部分

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

本页上的一些响应非常好,但确实导致了许多性能问题,例如挂起,主要是在没有连接的情况下。

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

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

不能解决在检查和运行代码之间网络中断的问题 但是相当可靠

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

NetworkInterface.GetIsNetworkAvailable非常不可靠。只是有一些VMware或其他局域网连接,它将返回错误的结果。 还有关于Dns.GetHostEntry方法,我只是关心测试URL是否可能在我的应用程序部署的环境中被阻止 所以我发现的另一种方法是使用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);
}

我不认为这是不可能的,只是不简单。

我已经建立了这样的东西,是的,它并不完美,但第一步是必不可少的:检查是否有任何网络连接。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;
}

这非常简单,但它确实有助于提高检查的质量,特别是当您想检查各种代理配置时。

所以:

  • 检查是否有网络连接(让这真的很好,甚至可以在出现误报时将日志发送给开发人员,以改进NetworkIsAvailable功能)
  • HTTP平
  • (循环代理配置,在每个代理上使用HTTP ping)
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;
}
}

ping google.com会引入一个DNS解析依赖。ping 8.8.8.8很好,但谷歌是几个跳离我。我所需要做的就是在互联网上ping离我最近的东西。

我可以使用Ping的TTL特性来ping跳#1,然后跳#2,等等,直到我从一个可路由地址上的某个东西得到回复;如果该节点在一个可路由地址上,那么它就在因特网上。对于我们大多数人来说,跳点1将是我们的本地网关/路由器,跳点2将是光纤连接或其他设备的另一侧的第一个点。

这段代码对我有用,比这个线程中的其他一些建议反应更快,因为它是在互联网上ping离我最近的任何东西。


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;
}
}
}
我已经看到了上面列出的所有选项,唯一可行的检查互联网是否可用的选项是“Ping”选项。 导入[DllImport("Wininet.dll")]System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()NetworkInterface类的任何其他变体都不能很好地检测网络的可用性。这些方法只检查网线是否插好

.使用实例

“Ping选项”

if(连接可用)返回true

if(连接不可用,网线已插入)返回false

if(网线未插入)

的NetworkInterface

if(Internet可用)返回True

if(Internet不可用,网线插入)返回True

if(Network Cable is Not Plugged)返回false

(DllImport(“Wininet.dll”)]

if(Internet可用)返回True

if(Internet不可用,网线插入)返回True

if(Network Cable is Not Plugged)返回false

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

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

我个人认为安东和莫菲特的答案最好,但我添加了一个检查,以排除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));
}

对于我的应用程序,我们也通过下载小文件进行测试。

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

这是如何在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
}
}

我有三个网络连接测试。

  • 引用System.NetSystem.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;
}
}

执行测试

如果你将StringBooleanDictionary称为CheckList,你可以将每个测试的结果添加到CheckList中。

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

如果CheckList包含trueValue,那么你知道有一个互联网连接。

我在我的3g路由器/调制解调器上的那些方法上有问题,因为如果互联网断开,路由器将页面重定向到它的响应页面,所以你仍然得到一个蒸汽,你的代码认为有互联网。 苹果(或其他)有一个热点删除页面,总是返回特定的响应。下面的示例返回“Success”响应。所以你会非常确定你可以连接互联网并得到真实的回应

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

多线程版本的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";
}
}
}

使用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");
}
}
}

尽量避免通过捕获异常来测试连接。因为我们真的预料到有时我们可能会失去网络连接。

 if (NetworkInterface.GetIsNetworkAvailable() &&
new Ping().Send(new IPAddress(new byte[] { 8, 8, 8, 8 }),2000).Status == IPStatus.Success)
//is online
else
//is offline

简介

在某些情况下,您需要在windows应用程序中使用c#代码检查internet是否可用。可能是在windows窗体中使用internet下载或上传文件,或从远程位置的数据库中获取一些数据,在这些情况下,internet检查是强制性的。

有一些方法可以从后面的代码中使用c#检查internet的可用性。这里解释了所有这些方法,包括它们的局限性。

  1. InternetGetConnectedState(经由wininet)

“wininet”API可以用来检查本地系统是否有活跃的互联网连接。用于此操作的命名空间是'System.Runtime。并使用DllImport导入dll' wininet.dll'。在此之后,创建一个带有extern static的布尔变量,函数名为InternetGetConnectedState,带有两个参数描述和reservedValue,如示例所示。

注意:extern修饰符用于声明外部实现的方法。当您使用Interop服务调用非托管代码时,extern修饰符的常见用法是与DllImport属性一起使用。在这种情况下,方法也必须声明为静态的。

接下来创建一个名称为IsInternetAvailable的boolean方法。的 上面的函数将用于这个返回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;
}
}
  1. GetIsNetworkAvailable

下面的示例使用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的另一个例子是,如果应用程序运行在连接到集线器或路由器的计算机上,而集线器或路由器失去了上行连接。

  1. 在网络上Ping一个主机名

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服务器)。

欢迎发表意见和建议。编码……快乐!

接受的答案成功的速度很快,但是当没有连接时失败的速度很慢。所以我想建立一个健壮的连接检查,它会更快地失败。

据说不是所有环境都支持ping,所以我从接受的答案开始,并从在这里添加了一个自定义超时的WebClient。你可以选择任何超时,但3秒对我来说是通过wifi连接的。我尝试添加一个快速迭代(1秒),如果第一个迭代失败,则添加一个缓慢迭代(3秒)。但是这没有意义,因为这两个迭代总是失败(当没有连接时)或总是成功(当连接时)。

我正在连接AWS,因为我想在连接测试通过时上传一个文件。

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

@ChaosPandion的答案基础上,为了尽可能确定结果是正确的,你可以像其他人指出的那样包括多个大网站。但是,这应该异步完成,以避免太长的等待时间。此外,WebRequest、HttpWebRequest和HttpWebResponse类现在已经过时,应该被HttpClient取代。以下示例考虑了上述因素:

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

该方法检查列表中的所有url,如果它们都不可访问,则返回false。我已经添加了苹果的url,因为在我的情况下,它加载相当快,但它可以替换为任何url。