Який найшвидший і найефективніший спосіб перевірити наявність підключення до Інтернету в .NET?
Windows NLM API
має бути найкращим для цього. stackoverflow.com/questions/5405895/…
Який найшвидший і найефективніший спосіб перевірити наявність підключення до Інтернету в .NET?
Windows NLM API
має бути найкращим для цього. stackoverflow.com/questions/5405895/…
Відповіді:
Щось подібне повинно працювати.
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
в Китаї, наприклад ...
Існує абсолютно ніякий спосіб, коли ви можете надійно перевірити, чи є підключення до Інтернету чи ні (я вважаю, ви маєте на увазі доступ до Інтернету).
Однак ви можете запитувати ресурси, які практично ніколи не є офлайн, як-от pinging 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
) загальнодоступних DNS для мене працює добре.
Beware - many schools and offices block the ping protocol.
якщо ви використовуєте цей метод для програми, яка буде використовуватися клієнтами, я б радив проти цього способу перевірки Інтернету
Замість перевірки просто виконайте дію (веб-запит, пошта, 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
Якщо мережа знищена, ваша дія вийде з ладу так само швидко, як пінг тощо.
1 - start to perform action
2 - if the net is down(or goes down) the action will fail
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);
}
Тест на підключення до Інтернету за допомогою pinging 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
}));
}
}
Я бачив усі перераховані вище варіанти, і єдиний життєздатний варіант перевірити, чи є в Інтернеті доступний чи ні - це варіант "Пінг". Імпорт [DllImport("Wininet.dll")]
та System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
будь-яка інша зміна NetworkInterface
класу не спрацьовує при виявленні доступності мережі. Ці методи перевіряють, чи підключений мережевий кабель чи ні.
"Варіант пінг"
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
немає способу дізнатися, чи є підключення до Інтернету.
Не вирішує проблему переходу мережі між перевіркою та запуском коду, але є досить надійною
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;
}
Pinging google.com вводить залежність від роздільної здатності DNS. Пінгінг 8.8.8.8 - це добре, але Google на кілька хмелів від мене. Все, що мені потрібно зробити - це надіслати на мене найближчу інформацію в Інтернеті.
Я можу використовувати функцію TTL Ping для пінг-хопу №1, потім скакання №2 тощо, поки не отримаю відповідь від того, що є за адресою маршрутизації; якщо цей вузол знаходиться за адресою маршрутизації, то він є в Інтернеті. Для більшості з нас, хоп №1 буде нашим локальним шлюзом / маршрутизатором, а перехід №2 стане першою точкою на іншій стороні нашого волоконного з'єднання або будь-якого іншого.
Цей код працює для мене і реагує швидше, ніж деякі інші пропозиції в цій темі, оскільки він переносить все, що мені найближче в Інтернеті.
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 Network List Manager, який доступний для Vista та Windows 7. Стаття MSDN тут . У статті наведено посилання на завантаження зразків коду, які дозволяють це зробити:
AppNetworkListUser nlmUser = new AppNetworkListUser();
Console.WriteLine("Is the machine connected to internet? " + nlmUser.NLM.IsConnectedToInternet.ToString());
Обов’язково додайте посилання на бібліотеку Network List 1.0 на вкладці COM ..., яка відображатиметься як NETWORKLIST.
Спробуйте уникати тестування з'єднань, перехопивши виняток. тому що ми дійсно очікуємо, що іноді ми можемо втратити мережевий зв’язок.
if (NetworkInterface.GetIsNetworkAvailable() &&
new Ping().Send(new IPAddress(new byte[] { 8, 8, 8, 8 }),2000).Status == IPStatus.Success)
//is online
else
//is offline
Якщо ви хочете повідомити користувача та вживати заходів, коли відбудеться зміна мережі / з'єднання.
Використовуйте API NLM:
Я особисто знаходжу відповідь Антона та 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
що все-таки буде вірно, навіть якщо мережа не підключена до Інтернету.
Багатопотокова версія 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 для моніторингу стану мережі та підключення до Інтернету.
Зразок:
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");
}
}
}
Вступ
У деяких сценаріях потрібно перевірити, чи доступний Інтернет чи не використовується код C # у програмах Windows. Це може бути завантаження або завантаження файлу за допомогою Інтернету у формах Windows або отримання деяких даних з бази даних, яка знаходиться у віддаленому місці, в цих ситуаціях перевірка в Інтернеті є обов'язковою.
Існує кілька способів перевірити наявність Інтернету за допомогою C # з коду позаду. Усі такі способи пояснюються тут, включаючи їх обмеження.
API "wininet" можна використовувати для перевірки того, чи локальна система має активне підключення до Інтернету чи ні. Простір імен, використовуваний для цього, є 'System.Runtime.InteropServices' та імпортує dll 'wininet.dll' за допомогою DllImport. Після цього створіть булеву змінну з зовнішньою статикою з назвою функції InternetGetConnectedState з описом двох параметрів та зарезервованою Value, як показано в прикладі.
Примітка: зовнішній модифікатор використовується для оголошення способу, який реалізується зовні. Загальне використання модифікатора зовнішнього використання - це атрибут DllImport, коли ви використовуєте служби Interop для входу в некерований код. У цьому випадку метод також повинен бути оголошений статичним.
Далі створіть метод з ім'ям "IsInternetAvailable" як булевим. Вищевказана функція буде використовуватися в цьому методі, який повертає статус Інтернет в локальній системі
[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 повернеться правдою. Наприклад, якщо пристрій, що запускає додаток, підключено до бездротової мережі, для якої потрібен проксі, але проксі не встановлено, GetIsNetworkAvailable поверне справжнє значення. Іншим прикладом, коли GetIsNetworkAvailable повернеться правдою, є те, якщо програма запущена на комп'ютері, підключеному до концентратора або маршрутизатора, де концентратор або маршрутизатор втратили з'єднання вгору.
Класи Ping і PingReply дозволяють програмі визначати, чи доступний віддалений комп'ютер по мережі, отримуючи відповідь від хоста. Ці класи доступні в просторі імен System.Net.NetworkInformation. Наведений нижче приклад показує, як пінг-хост.
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 вказує лише на те, що віддалений хост можна отримати в мережі; наявність послуг вищого рівня (наприклад, веб-сервера) на віддаленому хості не гарантується.
Коментарі / пропозиції запрошуються. Щасливого кодування ......!
Для моєї програми ми також перевіряємо завантаження крихітного файлу.
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;
}
Також. Деякий провайдер може використовувати середній сервер для кешування файлів. Додайте випадковий невикористаний параметр, наприклад. https://www.microsoft.com/favicon.ico?req=random_number Може запобігти кешування.
У мене виникають проблеми з цим методом на моєму 3g маршрутизаторі / модемі, тому що, якщо відключений Інтернет, маршрутизатор перенаправляє сторінку на свою сторінку відповідей, тож ви все одно отримуєте пара і ваш код думає, що є Інтернет. У яблук (або інших) є сторінка відміни «гарячої точки», яка завжди повертає певну відповідь. Наступний зразок повертає відповідь "Успіх". Тож ви будете точно впевнені, що зможете підключити Інтернет та отримати реальну відповідь!
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;
}
У мене є три тести на підключення до Інтернету.
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
, то ви знаєте, що є Інтернет.
public static bool HasConnection()
{
try
{
System.Net.IPHostEntry i = System.Net.Dns.GetHostEntry("www.google.com");
return true;
}
catch
{
return false;
}
}
Це працює