Проверьте, доступен ли доступ в Интернет

В моем приложении я хочу сделать сетевой вызов, только если у меня есть доступ к Интернету.

Примечание. Я подключен к точке Wi-Fi, где нет Интернета.

Я хочу проверить, доступен ли Интернет. Я попытался использовать Reachability, как описано здесь, а также попробовал более простое решение, как описано здесь

Проблема в том, что Reachability возвращает информацию о том, что Интернет доступен, когда это не так. Другое решение требует слишком много времени, чтобы дать ответ. Я пытался установить интервалы времени ожидания для запроса и сеанса, но он игнорируется.

Как я могу проверить доступность Интернета, если я подключен к Wi-Fi без Интернета?

Вот код, который я использую:

- (void) postAsyncTaskWithUrl:(NSString*)urlString
                      andType:(NSString*)requestType
                     andToken:(NSString*)token
          andPropertiesObject:(id)propObject
                   urlEncoded:(BOOL)isUrlEncoded
                  withSuccess:(nullable void(^)(id _Nullable))success
                   andFailure:(nullable void(^)(id _Nullable))failure
{

    internetReachableFoo = [Reachability reachabilityWithHostname:@"www.google.com"];

    __weak typeof(self) weakSelf = self;
    // Internet is reachable
    internetReachableFoo.reachableBlock = ^(Reachability*reach)
    {
                 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlSt];
        [request setTimeoutInterval:20]; //Ignored ... WHY?

        NSURLSessionConfiguration *sessionConfigurations = [NSURLSessionConfiguration defaultSessionConfiguration];
        [sessionConfigurations setTimeoutIntervalForRequest:20]; //Ignored ... WHY?
        [sessionConfigurations setTimeoutIntervalForResource:20]; //Ignored ... WHY?
//        NSURLSession *session = [NSURLSession sharedSession];
        NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfigurations];
        [[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {


     }

}

}

person Keselme    schedule 08.01.2020    source источник
comment
Вы можете проверить это: Как узнать, доступен ли фактический Интернет в Swift?   -  person nayem    schedule 08.01.2020


Ответы (3)


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

Согласно официальная документация Apple:

Всегда пытайтесь установить связь. Не пытайтесь угадать, доступна ли сетевая служба, и не кэшируйте это определение.

Похожие сообщения Джареда Синклера в блоге по этой теме, используя SCNetworkReachability (это то, что скрыто использует библиотека Reachability):

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

Заимствование из недавней темы Reddit:

Доступность — это одна из «этих тем» в мире iOS. Что означает доступность Интернета? Даже если вы проверите сетевые интерфейсы, вы не сможете получить доступ к apple.com или google.com. Даже если вы подключитесь к Google, вы не сможете получить доступ к своему локальному серверу или облаку. Если вы проверяете, можете ли вы связаться с интересующим вас сервером, почему бы не отправить запрос сразу?

person Seb Jachec    schedule 08.01.2020
comment
Спасибо за ответ, на самом деле я в порядке, пытаясь отправить запрос, не зная, есть ли интернет или нет, поэтому я попытался установить тайм-аут в 10 секунд, чего, я думаю, должно быть достаточно. Однако приложение полностью игнорирует это, и я больше минуты жду ответа. Что может привести к игнорированию тайм-аута? - person Keselme; 08.01.2020
comment
Я не уверен. Это может быть связано с тем, что тайм-аут завершает запрос только в том случае, если в течение 10 секунд не было передано абсолютно никаких данных, он не завершает запрос, если он начинается в течение 10 секунд, а затем продолжается 60 секунд (stackoverflow.com/a/35428764/447697) - person Seb Jachec; 08.01.2020

TL;DR: Возможно, вам нужен NSTimer.

В моем приложении я хочу сделать сетевой вызов, только если у меня есть доступ к Интернету.

Это не осмысленное заявление. Нет никакого теста, который вы могли бы выполнить, который надежно означает, что вы можете «получить доступ к Интернету» (несмотря на существование NSURLErrorNotConnectedToInternet, что на самом деле не означает, что он говорит). Например, ваш код пытается рассматривать "www.google.com" как "Интернет". Но вполне возможно иметь сеть, которая позволяет пакетам идти на www.google.com, но больше никуда. Или разрешить пакеты ICMP, но не пакеты HTTP. Или разрешить HTTP-пакеты, но не на определенные порты. Такие сетевые конфигурации не просто возможны, они распространены, и по-разному все они могут выглядеть как «не в Интернете».

Единственное, на что вы можете ответить, это «могу ли я отправить пакет на конкретный хост и получить пакет в ответ?» Невозможно даже узнать, можете ли вы просто отправить пакет. Если вы не получаете что-то взамен, вы не знаете, доставлена ​​ваша посылка или нет.

Достижимость отвечает на вопрос «если я попытаюсь отправить пакет, будет ли мой локальный сетевой стек вообще пытаться это сделать?» По сути, это вопрос о том, доступен ли первый переход в таблице маршрутизации. Это не означает, что вы действительно можете подключиться; он может только сказать вам, что это абсолютно не так.

Используемые вами тайм-ауты основаны на времени простоя в сеансе. Но вы никогда не запускаете сеанс, поэтому он никогда не простаивает. Тайм-аут, который вы ищете, - это тайм-аут TCP, который, как я ожидаю, составит 4 минуты. NSURLSession не может его настроить.

Если вам нужен тайм-аут «начало-окончание» настенных часов, вам нужно запустить его самостоятельно с помощью таймера .

person Rob Napier    schedule 08.01.2020
comment
вы говорите, что я никогда не начинаю сессию, но не вызов [[session dataTaskWithRequest:request completionHandler:handler] resume] означает, что я начинаю ее? - person Keselme; 09.01.2020
comment
Нет, я имею в виду, что сеанс TCP никогда не подключается, поэтому на уровне URLSession таймер простоя не запускается. - person Rob Napier; 09.01.2020
comment
Пробовал реализовать механизм NSTimer, но он тоже не работает, как только делаю dataTaskWithRequest при подключении к вайфаю без интернета все приложение зависает минут на две. Только когда он возвращается, срабатывает селектор таймера. Я не понимаю, что может вызвать это зависание, потому что, насколько я понимаю, dataTaskWithRequest работает в своем собственном потоке. - person Keselme; 09.01.2020

Если вы попытаетесь загрузить http://captive.apple.com, он вернет жестко заданную строку «Success» в качестве body, если интернет работает или будет перенаправлять/сбой. Вы можете проверить, что ответ начинается с 200, а тело — «успех». Это то, что Apple использует для автоматического отображения окна учетных данных при подключении к аэропорту, например, Wi-Fi. Говоря, что а) нет надежного решения б) вы будете тратить данные пользователя впустую (может быть, это нормально в вашем случае использования?)

person Sash Zats    schedule 12.01.2020