.NET でインターネット接続を確認する最も高速で効率的な方法は何ですか?
26 に答える
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;
}
}
インターネット接続があるかどうかを確実に確認する方法は絶対にありません(インターネットへのアクセスを意味していると思います)。
ただし、google.com などに ping を実行するなど、実質的にオフラインになることのないリソースをリクエストすることはできます。これは効率がいいと思います。
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;
}
チェックする代わりに、アクション (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
メソッドを使用することです。私のコードは
[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
google.com に ping を実行すると、DNS 解決の依存関係が発生します。ping8.8.8.8
は問題ありませんが、Google は私から数ホップ離れています。私がする必要があるのは、インターネット上にある私に最も近いものに ping することだけです。
の TTL 機能を使用Ping
してホップ #1、次にホップ #2 などに ping を実行し、ルーティング可能なアドレスにあるものから応答を得ることができます。そのノードがルーティング可能なアドレスにある場合、それはインターネット上にあります。ほとんどの場合、ホップ #1 はローカル ゲートウェイ/ルーターになり、ホップ #2 はファイバー接続の反対側の最初のポイントなどになります。
このコードは私にとってはうまくいき、このスレッドの他の提案よりも速く反応します。
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
(ネットワークケーブルが差し込まれていない)Throws an exception
ネットワーク インターフェイス
if
(インターネット利用可能)返品True
if
(インターネットが利用できず、ネットワーク ケーブルが接続されている)True
if
(ネットワーク ケーブルが接続されていません) を返しますfalse
[DllImport("Wininet.dll")]
if
(インターネット利用可能)返品True
if
(インターネットが利用できず、ネットワーク ケーブルが接続されている)True
if
(ネットワーク ケーブルが接続されていません) を返しますfalse
そのため、 インターネット接続が利用可能かどうかを知る方法はありません[DllImport("Wininet.dll")]
。 NetworkInterface
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;
}
}
不可能ではないと思いますが、簡単ではありません。
私はこのようなものを構築しました。はい、完璧ではありませんが、最初のステップは不可欠です。ネットワーク接続があるかどうかを確認することです。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 Ping
- (それぞれに HTTP Ping を使用してプロキシ構成を循環)
もう 1 つのオプションは、Vista および Windows 7 で使用できる Network List Manager API です。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 として表示されます。
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";
}
}
}
public static bool HasConnection()
{
try
{
System.Net.IPHostEntry i = System.Net.Dns.GetHostEntry("www.google.com");
return true;
}
catch
{
return false;
}
}
それはうまくいく