2015-02-02 3 views
3

Мне нужно определить локальный IP-адрес и маску подсети в сети WiFi на устройстве Android (для правильного расчета широковещательный адрес UDP строго для локальной подсети).Android, обнаружение локального IP и маски подсети для WiFi, как при подключении, так и при подключении к точке доступа

Когда устройство подключено к точке доступа, следующий работают правильно:

// Only works when NOT tethering 
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 

DhcpInfo dhcp = wifi.getDhcpInfo(); 
if (dhcp == null) 
    throw new IOException("No DHCPInfo on WiFi side."); 

foo(dhcp.ipAddress, dhcp.netmask); 

Но это не работает, когда это андроид устройство, обеспечивающее точку доступа, хотя привязывать: DhcpInfo, кажется, содержит информацию установленный сервером DCHP, когда Android-устройство является его клиентом, а не когда это устройство Android предоставляет услугу DHCP. Когда в привязывать, наиболее перспективным решением я смог найти:

// No way to get subnet mask 
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 

WifiInfo info = wifi.getConnectionInfo(); 
if (info == null) 
    throw new IOException("No connection info on WiFi side."); 

foo(info.getIpAddress(), info.??? /* netmask*/); 

EDIT: НЕПРАВИЛЬНО, в моих тестах даже это работает только, когда НЕ привязывать. Хотя привязка IP-адреса всегда равна 0.

Но нет ничего похожего на WifiInfo.getNetMask(), как я могу получить маску подсети в этом случае? (Это отсутствие кажется мне действительно странным, так как здесь имеется множество других сведений. Я не вижу чего-то очевидного?)

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

Даже стандартная Java (то есть не привязана к Android) NetworkInterface.getNetworkInterfaces(), похоже, не имеет способа получить маску подсети (кроме того, что она не позволяет различать, что соответствует WiFi). Что мне не хватает?

+0

Пожалуйста, напишите Ваше решение в качестве ответа на свой вопрос (http://stackoverflow.com/help/self-answer).Затем отметьте его как принятый ответ. Это поможет другим uisers быстрее найти решение. Если вовремя есть лучшее решение, вы всегда можете обновить ответ или отправить второй и отметить это как рабочий ответ. Это позволит сохранить информацию о более старых версиях. –

+1

Готово. Спасибо за подсказку. – GozzoMan

ответ

4

Лучшее решение, которое я нашел на данный момент:

Это сбивает с толку меня, как информация/интерфейс о привязывать настолько громоздким/скрыт, чтобы получить, и еще не приняты во внимание, когда вы получаете информацию от WifiManager или ConnectivityManager для типа Wifi: все работает только тогда, когда НЕ подключен. Я действительно потерял эту ветку расследования.

Лучшее решение, которое я нашел на данный момент, использует стандартный Java NetworkInterface.getNetworkInterfaces(), а не любой API Android.

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

// This works both in tethering and when connected to an Access Point 

    Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); 

    while (interfaces.hasMoreElements()) 
    { 
     NetworkInterface networkInterface = interfaces.nextElement(); 

     if (networkInterface.isLoopback()) 
      continue; // Don't want to broadcast to the loopback interface 

     for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) 
     { 
       InetAddress broadcast = interfaceAddress.getBroadcast(); 

       // InetAddress ip = interfaceAddress.getAddress();     
       // interfaceAddress.getNetworkPrefixLength() is another way to express subnet mask 

       // Android seems smart enough to set to null broadcast to 
       // the external mobile network. It makes sense since Android 
       // silently drop UDP broadcasts involving external mobile network. 
       if (broadcast == null) 
        continue; 

       ... // Use the broadcast     
     } 
    } 

Что касается маски подсети, результат от getNetworkPrefixLength() может быть принужден в маску подсети. Я использовал getBroadcast(), так как это была моя конечная цель.

Для этого кода не требуется специальных разрешений (no ACCESS_WIFI_STATE или NETWORK, всего INTERNET).

Первичная ссылка на фрагмент кода: http://enigma2eureka.blogspot.it/2009/08/finding-your-ip-v4-broadcast-address.html