Какой самый быстрый и эффективный способ проверить подключение к Интернету в .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
) работает нормально для меня.
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);
}
Тест для подключения к интернету с помощью пинг 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;
}
Пинг google.com вводит зависимость разрешения DNS. Pinging 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());
Обязательно добавьте ссылку на библиотеку типов сети 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
Если вы хотите уведомить пользователя / выполнить действие при каждом изменении сети / соединения.
Использовать NLM API:
Лично я считаю, что Антон и Моффельте лучше всего отвечают , но я добавил проверку, чтобы исключить виртуальные сети, созданные 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. После этого создайте логическую переменную с extern static с именем функции InternetGetConnectedState с описанием двух параметров и reservedValue, как показано в примере.
Примечание. Модификатор extern используется для объявления метода, который реализован извне. Обычно используется модификатор extern с атрибутом 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 возвращает значение true. Например, если устройство, на котором запущено приложение, подключено к беспроводной сети, для которой требуется прокси-сервер, но прокси-сервер не задан, GetIsNetworkAvailable вернет значение true. Другой пример того, когда GetIsNetworkAvailable вернет true, - это если приложение работает на компьютере, который подключен к концентратору или маршрутизатору, где концентратор или маршрутизатор потерял восходящее соединение.
Классы 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;
}
}
Это работает