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

Возможный дубликат:
Как проверить наличие интернет-соединения в java?

Я хочу посмотреть, есть ли у кого-нибудь простой способ определить, есть ли интернет-соединение при использовании Java. Текущее приложение использовало метод InternetGetConnectedState в библиотеке WinInit для Windows, но мое приложение должно быть кросс-платформенным для работы с Mac, и этот способ не будет работать. Я даже не знаю JNI, чтобы использовать DLL на Java, и это быстро расстроило.

Только способы, о которых я мог думать, - это tring, чтобы открыть URL-соединение с веб-сайтом, и если это не удается, верните false. Мой другой путь ниже, но я не знал, стабильно ли это. Если я отключу свой сетевой кабель, я получаю исключение UnknownHostException при попытке создать InetAddress. В противном случае, если кабель подключен, я получаю действительный объект InetAddress. Я не тестировал ниже код на Mac.

Спасибо за любые примеры или советы, которые вы можете предоставить.

UPDATE: последний блок кода находится внизу. Я решил воспользоваться рекомендацией HTTP-запроса (в данном случае Google). Он прост и отправляет запрос на сайт для получения данных. Если я не могу получить какой-либо контент из соединения, нет Интернета.

public static boolean isInternetReachable()
        {
            try {

                InetAddress address = InetAddress.getByName("java.sun.com");

                if(address == null)
                {
                    return false;
                }

            } catch (UnknownHostException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return false;
            }
            catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return false;
            }
            return true;
        }

Заключительный код:

//checks for connection to the internet through dummy request
        public static boolean isInternetReachable()
        {
            try {
                //make a URL to a known source
                URL url = new URL("http://www.google.com");

                //open a connection to that source
                HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection();

                //trying to retrieve data from the source. If there
                //is no connection, this line will fail
                Object objData = urlConnect.getContent();

            } catch (UnknownHostException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return false;
            }
            catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return false;
            }
            return true;
        }

Ответ 1

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

Другая вещь, которую следует помнить, заключается в том, что вам нужно будет установить системное свойство, чтобы отключить кэширование DNS в среде java. В противном случае он может продолжать сообщать, что сеть основана на кэшированных данных (даже если она не работает).

Другим подходом было бы фактически открыть HTTP-запрос к некоторому сетевому адресу, например, так часто.

Ответ 2

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

В моем случае при тестировании с одним адресом метод вернет true, но займет 10 секунд или больше, чтобы получить ответ. В этом случае сервер был доступен, но не для каких-либо полезных целей, так как соединение было настолько медленным. Это происходит потому, что таймаут по умолчанию для HttpURLConnection равен 0 или бесконечен.

По этой причине я рекомендую вам выполнить проверку потока пользовательского интерфейса и добавить urlConnect.setConnectTimeout(1000); до, вызвав urlConnect.getContent();

Таким образом, вы знаете, что адрес доступен, и что для загрузки файла 10k потребуется 5 лет.

(Конечно, вы можете изменить время таймаута в соответствии с вашими потребностями)

Также я бы рекомендовал не проверять общий адрес (google.com и т.д.), если ваша программа обычно не имеет доступа к нескольким доменам. Если вы просто обращаетесь к одному или двум, проверьте этот домен.

Ответ 3

Обратите внимание, что он может вернуть false, если java.sun.com не отвечает! В этом случае вы должны проверить другой сайт, чтобы быть уверенным.

Ответ 4

Не проверял это, но я предлагаю посмотреть на java.net.NetworkInterface.getNetworkInterfaces(). Это возвращает перечисление всех сетевых интерфейсов на машине или null, если их нет.

Я не уверен, если можно с уверенностью предположить, что ненулевой ответ обеспечивает правильное сетевое подключение - в зависимости от ваших потребностей вам может понадобиться или не нужно отфильтровывать петлевые адреса (что, я думаю, вы могли бы сделать с java.net.NetworkInterface.getInetAddresses() для каждого возвращаемого сетевого интерфейса, а затем вызывает InetAddress.isLoopbackAddress() для каждого из них.)

Ответ 5

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

Кроме того, не забудьте спросить пользователя, прежде чем пытаться связаться.

Ответ 6

Вопрос не имеет значения. Нет такой вещи, как "подключение к Интернету". Вы должны попытаться создать его. В упомянутом API Windows упоминается только, набирается ли ваш модем или нет, и я видел, что он фактически вызывает dial-ins, что не совсем так. Не то, чтобы у меня был набор номера в течение последних 8 лет или около того.

Ответ 7

Проблема с первым решением заключается в том, что InetAddress имеет кэш, поэтому, когда вы теряете соединение для следующих нескольких вызовов, имя разрешается через кеш java. При использовании URL-адреса aproach у вас возникла проблема с использованием getContent, который должен извлекать html, чтобы у вас было потребление данных. Если вызовы выполняются очень часто, это может быть проблемой (более того, если у вас нет неограниченного плана данных на устройстве, на котором запущено программное обеспечение).

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