Android - проверьте подключение к интернету через определенную сеть (wifi).

По сути, мне нужно проверить, есть ли у моего Wi-Fi-соединения доступ в Интернет. Самый эффективный способ, который я знаю, - это sock.connect (), но мне нужно быть уверенным, что соединение будет осуществляться через сеть Wi-Fi, и это моя основная проблема, Я искал об этом несколько дней, и на это нет хорошего ответа.

Есть много решений, таких как Как узнать, подключен ли Wi-Fi на Android?, но они проверяют только, подключено ли устройство к маршрутизатору. Мне нужно знать, есть ли у маршрутизатора доступ в Интернет.

Мое лучшее приближение было таким:

        Socket sock = new Socket();
        ConnectivityManager
                cm = (ConnectivityManager) mContext.getApplicationContext()
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            Network net = cm.getActiveNetwork();
            net.bindSocket(sock);
        }
        sock.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
        sock.close();

Но здесь есть некоторые ограничения. Самое большое ограничение - это то, что работает только для API> = 23. Кроме того, если я нахожусь в Китае, я думаю, что имя хоста «8.8.8.8» не будет работать, верно?

И, наконец, cm.getActiveNetwork () будет сетью WIFI только в том случае, если мое устройство подключено к сети Wi-Fi, и это не совсем так, потому что можно изменить активную сеть по умолчанию.

Что мне нужно знать:

  • Есть ли рабочая альтернатива для API> = 16?
  • Есть ли хорошее имя хоста, которое будет нормально работать в Китае?

Любая помощь будет оценена по достоинству, Заранее спасибо!

Возможный дубликат Как узнать, подключен ли Wi-Fi на Android?

owl777 13.09.2018 21:36

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

Daniel S. 13.09.2018 21:46
1
2
298
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Да, чтобы быть уверенным, вам нужно обратиться к удаленному серверу.

Обычный способ будет таким:

NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
if (isConnected) {
    try {
        InetAddress ipAddr = InetAddress.getByName("google.com");
        if (ipAddr.isReachable(5000)) {
            // Internet access OK!
        }
    } catch (Exception e) {
        // Error handling...
    }
}

Предпочитайте доменные имена при вызове getByName, а не IP-адреса (https://docs.oracle.com/javase/7/docs/api/java/net/InetAddress.html#getByName(java.lang.String))

Если вы хотите избежать использования диспетчера подключений, вы можете зарегистрировать BroadcastReceiver для событий WifiManager.NETWORK_STATE_CHANGED_ACTION, и вы будете знать, подключены ли вы к Wi-Fi (текущее состояние получается почти сразу).

Что касается проблемы с регионом, у меня нет идей, может быть, использовать серверы NTP вместо Google (гораздо более невинные серверы) или попробовать Baidu !?

Да, я сделал что-то подобное, но я хочу проверить доступ в Интернет через соединение Wi-Fi. С вашим решением я не могу этого гарантировать. Также isReachable () не работает должным образом, я использовал его для другой цели, и у вас может быть доступ в Интернет, а isReachable () в любом случае может вернуть false :(

Daniel S. 13.09.2018 22:35

На самом деле нельзя быть уверенным на 100%. Вы можете полагаться на тот факт, что если Wi-Fi подключен, это наиболее вероятное средство для выполнения сетевых операций, а не через мобильные данные или около того (но вы не можете быть уверены в c). И действительно, isReachable не идеален. Существует проблема кеширования DNS (многие виновники, локальные, маршрутизаторы, интернет-провайдеры), поэтому жизнь тяжелая. Вы можете попробовать это вместо isReachable: if (! IpAddr.equals ("")) ...

Regulus 13.09.2018 22:46
Ответ принят как подходящий

Наконец, я пришел к решению:

    public interface Consumer {
    void accept(Boolean internet);
}

class InternetCheck extends AsyncTask<Void, Void, Boolean> {

    private Consumer mConsumer;

    public InternetCheck(Consumer consumer) {
        mConsumer = consumer;
        execute();
    }

    @Override
    protected Boolean doInBackground(Void... voids) {
        Socket socket = null;
        try {
            WifiManager wifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
            if (wifiManager != null) {
                socket = new Socket();
                socket.setKeepAlive(false);
                String localIpAddress = getIpAddress(wifiManager);
                socket.bind(new InetSocketAddress(localIpAddress, 0));
                socket.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
                return true;
            }
            return false;
        } catch (IOException e) {
            //unbind();
            return false;
        }finally {
            if(socket != null && !socket.isClosed()) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    protected void onPostExecute(Boolean internet) {
        mConsumer.accept(internet);
    }
}

public static String getIpAddress(WifiManager wifiManager) {
    WifiInfo wifiInfo = wifiManager.getConnectionInfo();
    int ipAddress = wifiInfo.getIpAddress();
    return String.format(Locale.getDefault(), "%d.%d.%d.%d", (ipAddress & 0xff), (ipAddress >> 8 & 0xff),
            (ipAddress >> 16 & 0xff), (ipAddress >> 24 & 0xff));
}

Я пришел к решению после того, как увидел этот вопрос. Благодаря этому я получил IP-адрес моего Wi-Fi-соединения, и с его помощью я смог привязать сокет (socket.bind (...)) к Wi-Fi-соединению и проверить, есть ли у моего маршрутизатора доступ в Интернет.

Надеюсь, это решение кому-нибудь поможет в будущем :)

Другие вопросы по теме