Что является лучшим способом, чтобы проверить подключение к интернету using.NET?


каков самый быстрый и эффективный способ проверки подключения к Интернету в .NET?

23 185

23 ответа:

что-то вроде этого должно работать.

System. Net. WebClient

public static bool CheckForInternetConnection()
{
    try
    {
        using (var client = new WebClient())
        using (client.OpenRead("http://clients3.google.com/generate_204"))
        {
            return true;
        }
    }
    catch
    {
        return false;
    }
}

нет абсолютно никакого способа, вы можете надежно проверить, если есть подключение к интернету или нет (я предполагаю, что вы имеете в виду доступ к интернету).

однако вы можете запрашивать ресурсы, которые практически никогда не находятся в автономном режиме, например 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;
}

вместо проверки просто выполните действие (веб-запрос, почта, 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);         
}

Я не согласен с людьми, которые заявляют: "какой смысл проверять подключение перед выполнением задачи, так как сразу после проверки соединение может быть потеряно". Конечно, существует определенная степень неопределенности во многих задачах программирования, которые мы, как разработчики, берем на себя, но снижение неопределенности до уровня принятия является частью проблемы.

недавно я столкнулся с этой проблемой, создав приложение, которое включает в себя функцию отображения, связанную с он-лайн плиткой сервер. Эта функция должна была быть отключена, когда было отмечено отсутствие подключения к интернету.

некоторые из ответов на этой странице были очень хорошими, но тем не менее вызвали много проблем с производительностью, таких как зависание, в основном в случае отсутствия подключения.

вот решение, которое я в конечном итоге с помощью, с помощью некоторых из этих ответов и моих коллег:

         // 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
            }));
        }
    }

тест на подключение к интернету с помощью pinging Google:

new Ping().Send("www.google.com.mx").Status == IPStatus.Success

не решает проблему отключения сети между проверкой и запуском кода но довольно надежно

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;
}

я видел все варианты, перечисленные выше, и единственный жизнеспособный вариант, чтобы проверить вянут интернет доступен или нет, это вариант "пинг". Импорт [DllImport("Wininet.dll")] и System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces() или любой другой вариант NetworkInterface класс не работает хорошо в обнаружении доступности сети.Эти методы только проверяют, подключен ли сетевой кабель или нет.

опция "Ping"

if(соединение доступно) возвращает true

if(соединение недоступно и сетевой кабель подключен) возвращает false

if(сетевой кабель не подключен) Throws an exception

В Сетевом Интерфейсе

if(интернет)возвращает True

if(Интернет недоступен и сетевой кабель подключен ) возвращает True

if(сетевой кабель не подключен )возвращает false

The [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;
    }
}

пинг google.com вводит зависимость разрешения DNS. Pinging 8.8.8.8 в порядке, но Google находится в нескольких прыжках от меня. Все, что мне нужно сделать, это пинговать ближайшую ко мне вещь, которая находится в интернете.

Я могу использовать функцию TTL Ping для ping hop #1, затем hop #2 и т. д., Пока я не получу ответ от чего-то, что находится на маршрутизируемом адресе; если этот узел находится на маршрутизируемом адресе, то он находится в интернете. Для большинства из нас hop #1 будет нашим локальным шлюзом / маршрутизатором, а hop #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
    }
}

другой вариант-это API Network List Manager, который доступен для Vista и Windows 7. В статье здесь. В статье приведена ссылка на скачивание примеров кода, которые позволяют это сделать:

AppNetworkListUser nlmUser = new AppNetworkListUser();
Console.WriteLine("Is the machine connected to internet? " + nlmUser.NLM.IsConnectedToInternet.ToString());

обязательно добавьте ссылку на библиотеку типов Network List 1.0 на вкладке COM... который будет отображаться как NETWORKLIST.

Я лично нахожу ответ Антон и 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));
}

Если вы хотите уведомить Пользователя / принять меры при каждом изменении сети/соединения.
Используйте NLM API:

Я бы не подумал, что это невозможно, просто не просто.

Я построил что-то вроде этого, и да, это не идеально, но первый шаг имеет важное значение: чтобы проверить, есть ли подключение к сети. 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 Pings на каждом)
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;
    }
}
bool bb = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();

if (bb == true)
    MessageBox.Show("Internet connections are available");
else
    MessageBox.Show("Internet connections are not available");

многопоточная версия 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";
          }
      }
  }

использовать 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");
        }
    }
}

для моего приложения, мы также испытание скачать маленький файл.

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, и ваш код думает, что есть интернет. Яблоки (или другие) имеют страницу выделения горячих точек, которая всегда возвращает определенный ответ. Следующий пример возвращает ответ" Success". Таким образом, вы будете точно уверены, что вы можете подключить интернет и получить реальный ответ !

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
  • добавить следующие тестовые функции:

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;
    }
}

работает