什么是在.NET中检查互联网连接的最快最有效的方法?
您可以使用以下代码,这段代码也适用于伊朗和中国 -
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;
}
8.8.8.8
或8.8.4.4
)进行ping是有效的。 - Mangesh不要进行检查,直接执行操作(网页请求、电子邮件、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
方法。
我的代码是:
[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.com进行ping操作会涉及到DNS解析的依赖。对8.8.8.8
进行ping操作没问题,但是Google离我很远。我所需要做的就是ping互联网上距离我最近的东西。
我可以使用Ping
的TTL(生存时间)功能来ping第一跳,然后ping第二跳,直到我从一个可路由的地址收到回复;如果该节点在可路由的地址上,则它在互联网上。对于我们大多数人来说,第一跳将是我们的本地网关/路由器,而第二跳将是我们光纤连接或其他任何东西另一端的第一个点。
这段代码对我有效,并且响应速度比本帖中的一些其他建议更快,因为它会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 Google进行测试:
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
(网络电缆未插入)抛出异常
网络接口
if
(互联网可用)返回True
if
(互联网不可用且网络电缆已插入)返回True
if
(网络电缆未插入)返回false
[DllImport("Wininet.dll")]
if
(互联网可用)返回True
if
(互联网不可用且网络电缆已插入)返回True
if
(网络电缆未插入)返回false
因此,在[DllImport("Wininet.dll")]
和NetworkInterface
的情况下,没有办法知道互联网连接是否可用。
这并不能解决在检查和运行代码之间网络中断的问题,但相当可靠。
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;
}
BytesSent
和BytesReceived
之外,您基本上只是复制了已经在GetIsNetworkAvailable
中存在的功能。 - AnorZaken这里 是如何在安卓中实现的。
作为概念证明,我将这段代码翻译成了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
}
}
Windows NLM API
应该是最适合的。https://dev59.com/02035IYBdhLWcg3wePzf#60585095 - Mahbubur Rahman