Каков самый быстрый и эффективный способ проверки подключения к Интернету в .NET?
Как лучше всего проверить подключение к Интернету с помощью .NET?
Ответы (26)
Абсолютно невозможно надежно проверить, есть ли подключение к Интернету (я полагаю, вы имеете в виду доступ к Интернету).
Однако вы можете запрашивать ресурсы, которые практически никогда не отключены, например, 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
) у меня работает нормально.
- person Mangesh; 16.01.2015
Beware - many schools and offices block the ping protocol.
Если вы используете этот метод для приложения, которое будет использоваться клиентами, я бы посоветовал не использовать этот метод проверки в Интернете.
- person user1; 29.04.2015
Вместо проверки просто выполните действие (веб-запрос, почта, 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
невозможно узнать, доступно ли подключение к Интернету.
Проверка связи с google.com вводит зависимость разрешения DNS. Пинг 8.8.8.8 - это нормально, но Google находится в нескольких шагах от меня. Все, что мне нужно сделать, это проверить связь с ближайшим ко мне объектом в Интернете.
Я могу использовать функцию TTL Ping для проверки связи с переходом №1, затем с переходом №2 и т. Д., Пока я не получу ответ от чего-то, что находится на маршрутизируемом адресе; если этот узел находится на маршрутизируемом адресе, значит, он находится в Интернете. Для большинства из нас переход №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;
}
}
}
Не решает проблему отключения сети между проверкой и запуском кода, но достаточно надежен
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
.
- person AnorZaken; 26.03.2021
Старайтесь избегать тестирования соединений, перехватывая исключение. потому что мы действительно ожидаем, что иногда мы можем потерять сетевое соединение.
if (NetworkInterface.GetIsNetworkAvailable() &&
new Ping().Send(new IPAddress(new byte[] { 8, 8, 8, 8 }),2000).Status == IPStatus.Success)
//is online
else
//is offline
Вот, как это реализовано в 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
}
}
Другой вариант - API диспетчера списка сетей, доступный для Vista и Windows 7. Статья MSDN здесь. В статье есть ссылка на скачивание примеров кода, которые позволяют вам это делать:
AppNetworkListUser nlmUser = new AppNetworkListUser();
Console.WriteLine("Is the machine connected to internet? " + nlmUser.NLM.IsConnectedToInternet.ToString());
Обязательно добавьте ссылку на Библиотеку типов списка сетей 1.0 на вкладке COM ... которая будет отображаться как СПИСОК СЕТИ.
Я бы не подумал, что это невозможно, просто непросто.
Я построил что-то подобное, и да, это не идеально, но первый шаг важен: проверить, есть ли какое-либо сетевое подключение. 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;
}
Это довольно просто, но действительно помогает улучшить качество проверки, особенно если вы хотите проверить различные конфигурации прокси.
So:
- Проверьте, есть ли подключение к сети (сделайте это действительно хорошо, возможно, даже отправьте журналы обратно разработчикам, когда есть ложные срабатывания, чтобы улучшить функцию NetworkIsAvailable)
- HTTP-пинг
- (Циклическое переключение конфигураций прокси с HTTP-запросами на каждом)
Вступление
В некоторых сценариях вам нужно проверить, доступен ли Интернет или нет, используя код C # в приложениях Windows. Можно загрузить или загрузить файл через Интернет в формах Windows или получить некоторые данные из базы данных, которая находится в удаленном месте, в этих ситуациях проверка через Интернет является обязательной.
Есть несколько способов проверить доступность Интернета с помощью C # из исходного кода. Здесь объясняются все такие способы, включая их ограничения.
- InternetGetConnectedState (wininet)
API wininet можно использовать для проверки наличия активного подключения к Интернету в локальной системе. Для этого используется пространство имен System.Runtime.InteropServices, а импортируйте dll wininet.dll с помощью DllImport. После этого создайте логическую переменную с extern static с именем функции InternetGetConnectedState с описанием двух параметров и зарезервированнымValue, как показано в примере.
Примечание. Модификатор extern используется для объявления метода, который реализуется извне. Обычно модификатор extern используется с атрибутом DllImport, когда вы используете службы взаимодействия для вызова неуправляемого кода. В этом случае метод также должен быть объявлен как статический.
Затем создайте метод с логическим именем 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
В следующем примере используется метод 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 указывает только на то, что удаленный хост доступен в сети; наличие служб более высокого уровня (например, веб-сервера) на удаленном узле не гарантируется.
Комментарии / предложения приветствуются. Удачного кодирования ......!
Если вы хотите уведомлять пользователя / предпринимать действия всякий раз, когда происходит изменение сети / подключения.
Используйте 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));
}
Многопоточная версия 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";
}
}
}
принятый ответ выполняется быстро, но очень медленно завершается сбоем при отсутствии соединения. Поэтому я хотел создать надежную проверку соединения, которая бы быстрее выходила из строя.
Сообщается, что пинг поддерживается не во всех средах, поэтому я начал с принятого ответа и добавил WebClient из здесь с настраиваемый тайм-аут. Вы можете выбрать любой тайм-аут, но у меня работало 3 секунды при подключении через Wi-Fi. Я попытался добавить быструю итерацию (1 секунду), а затем медленную итерацию (3 секунды), если первая не удалась. Но это не имело смысла, поскольку обе итерации всегда терпели неудачу (когда не были подключены) или всегда заканчивались успехом (когда были подключены).
Я подключаюсь к AWS, так как хочу загрузить файл после прохождения теста подключения.
public static class AwsHelpers
{
public static bool GetCanConnectToAws()
{
try
{
using (var client = new WebClientWithShortTimeout())
using (client.OpenRead("https://aws.amazon.com"))
return true;
}
catch
{
return false;
}
}
}
public class WebClientWithShortTimeout: WebClient
{
protected override WebRequest GetWebRequest(Uri uri)
{
var webRequest = base.GetWebRequest(uri);
webRequest.Timeout = 5000;
return webRequest;
}
}
Используйте 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");
}
}
}
Вы можете использовать метод NetworkInterface.GetIsNetworkAvailable
, который указывает, доступно ли какое-либо сетевое соединение.
Попробуй это:
bool connection = NetworkInterface.GetIsNetworkAvailable();
if (connection == true)
{
MessageBox.Show("The system is online");
}
else {
MessageBox.Show("The system is offline";
}
Для моего приложения мы также тестируем, скачивая крошечный файл.
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-маршрутизаторе / модеме, потому что, если Интернет отключен, маршрутизатор перенаправляет страницу на свою страницу ответа, поэтому вы все равно получаете Steam, а ваш код думает, что есть Интернет. У Apple (или других) есть страница с горячими точками, которая всегда возвращает определенный ответ. В следующем примере возвращается ответ «Успешно». Так что вы будете точно уверены, что сможете подключиться к Интернету и получить реальный отклик!
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;
}
}
Это работает
using (var client = new WebClient() { Proxy = null })
на моем компьютере это будет быстрее;)
- person Tono Nam; 25.09.2013
I cannot image a world where www.google.com does not return some HTML
, например, в Китае ...
- person Jérôme MEVEL; 27.10.2016
public static bool ConnectedToAnyOf(params System.Uri[] url) { using (var wc = new System.Net.WebClient()) { for (var index = 0; index < url.Length; index++) { try { using (wc.OpenRead(url[index])) { return true; } } catch { } } } return false; }
- person Rob; 11.04.2019
http://google.com/generate_204
- person Zeeshanef; 09.04.2021
bb
все равно будет истинным, даже если сеть не подключена к Интернету.
- person halfpastfour.am; 17.05.2013
Windows NLM API
должен быть лучшим для этого. stackoverflow.com/questions/5405895/ - person Mahbubur Rahman   schedule 08.03.2020