.NETでインターネット接続を確認するための最速かつ最も効率的な方法は何ですか?
このような何かが動作するはずです。
public static bool CheckForInternetConnection()
{
try
{
using (var client = new WebClient())
using (client.OpenRead("http://clients3.google.com/generate_204"))
{
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
「タスクの実行前に接続をチェックする意味は何ですか、チェック直後に接続が失われる可能性があります」と述べている人々には同意しません。開発者として私たちが行う多くのプログラミングタスクには確かにある程度の不確実性がありますが、不確実性を許容レベルまで減らすことは課題の一部です。
私は最近、オンラインタイルサーバーにリンクするマッピング機能を含むアプリケーションを作成する際にこの問題に遭遇しました。この機能は、インターネット接続の欠如が指摘された場合は無効にする必要がありました。
このページの応答の一部は非常に良好でしたが、主に接続性がない場合に、ハングなどのパフォーマンスの問題を引き起こしました。
これらの答えのいくつかと同僚の助けを借りて、私が最終的に使用したソリューションは次のとおりです:
// 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
The NetworkInterface
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;
}
こちら 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;
}
}
Google.comにpingを実行すると、DNS解決の依存関係が発生します。 8.8.8.8のPingは問題ありませんが、Googleは私から数ホップ離れています。私がする必要があるのは、インターネット上にある私に最も近いものにpingを実行することです。
ルーティング可能なアドレスにあるものから応答が返されるまで、PingのTTL機能を使用して、ホップ#1、次にホップ#2などをpingできます。そのノードがルーティング可能なアドレス上にある場合、インターネット上にあります。私たちのほとんどにとって、ホップ#1はローカルゲートウェイ/ルーターになり、ホップ#2はファイバー接続の反対側の最初のポイントなどになります。
このコードは私のために機能し、インターネット上で私に最も近いものを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;
}
}
}
もう1つのオプションは、VistaおよびWindows 7で使用可能なNetwork List Manager APIです。MSDNの記事 here 。記事には、これを行うことができるコードサンプルをダウンロードするためのリンクがあります。
AppNetworkListUser nlmUser = new AppNetworkListUser();
Console.WriteLine("Is the machine connected to internet? " + nlmUser.NLM.IsConnectedToInternet.ToString());
必ずCOMタブからNetwork List 1.0 Type Libraryへの参照を追加してください... NETWORKLISTとして表示されます。
個人的には Anton and moffeltje bestの答えを見つけましたが、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));
}
ネットワーク/接続の変更が発生するたびにユーザーに通知する/アクションを実行する場合。
NLM APIを使用:
NetworkMonitor を使用して、ネットワーク状態とインターネット接続を監視します。
サンプル:
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");
}
}
}
これを試して:
using System.Net.NetworkInformation;
bool isNetAvailable = NetworkInterface.GetIsNetworkAvailable();
bool bb = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
if (bb == true)
MessageBox.Show("Internet connections are available");
else
MessageBox.Show("Internet connections are not available");
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;
}
}
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;
}
これは非常に簡単ですが、特にさまざまなプロキシ構成を確認する場合は、チェックの品質を向上させるのに役立ちます。
そう: