Обнаружение всех доступных сетевых широковещательных адресов в Java - PullRequest
15 голосов
/ 03 февраля 2011

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


private ArrayList<InetAddress> getBroadcastAddresses() {
        ArrayList<InetAddress> listOfBroadcasts = new ArrayList();
        Enumeration list;
        try {
            list = NetworkInterface.getNetworkInterfaces();

            while(list.hasMoreElements()) {
                NetworkInterface iface = (NetworkInterface) list.nextElement();

                if(iface == null) continue;

                if(!iface.isLoopback() && iface.isUp()) {
                    System.out.println("Found non-loopback, up interface:" + iface);

                    Iterator it = iface.getInterfaceAddresses().iterator();
                    while (it.hasNext()) {
                        InterfaceAddress address = (InterfaceAddress) it.next();

                        System.out.println("Found address: " + address);

                        if(address == null) continue;
                        InetAddress broadcast = address.getBroadcast();
                        if(broadcast != null) listOfBroadcasts.add(broadcast);
                    }
                }
            }
        } catch (SocketException ex) {
            return new ArrayList<InetAddress>();
        }

        return site;
}

Он работает довольно хорошо для регулярной локальной сети, однако когда дело доходит до беспроводной локальной сети, он просто пропускает второй цикл while после одного шага, поскольку address равно нулю, хотя когда я использовал System.out.println(interfaceItem) только для просмотра интерфейсов. Проходя через это, записали имя беспроводной локальной сети и мой IP, соответствующий сети.

РЕДАКТИРОВАТЬ 1: Это - это выход, где 172.16.1.104 - мой IP в беспроводной сети. Проблема появляется ТОЛЬКО на моем ноутбуке с Wi-Fi. Вывод из моего ноутбука, где я в основном использую беспроводную связь, а иногда я использую UTP для соединения с моим другом. На моем ноутбуке также есть один сетевой интерфейс VirtualBox.

Не могли бы вы сказать мне, что с ним не так? Спасибо!

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

Все еще люблю тебя! ; -)

1 Ответ

5 голосов
/ 09 февраля 2011

Я думаю, вам нужно будет перебрать все адреса и дополнительно проверить, является ли широковещательный адрес также null.

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

Вам необходимо полностью удалить часть кода 1st way. Когда вы наберете continue;, вы перейдете к следующему интерфейсу, а не рассматриваете возможность наличия двух адресов.

Другая причина, по которой вы всегда хотите перебирать все адреса, которые могут иметь широковещательные сообщения, заключается в том, что вам нужно учитывать, что у вас могут быть адреса в двух сетях, назначенных интерфейсу. Например, у вас может быть интерфейс с назначенными 192.168.0.1/24 и 172.16.0.1/24.

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

Наконец, поскольку использование широковещательных адресов ограничит вас общением только с хостами, которые имеют IP-адрес в одной подсети, вы можете пропустить хосты, которые не настроены должным образом с одной подсетью / маской сети. Так что вы можете рассмотреть возможность использования многоадресной рассылки для этого; Вы можете использовать IPv4 (или IPv6 ) для многоадресных адресов всех узлов, чтобы достичь всех хостов в подсети, независимо от настроенного адреса. (224.0.0.1 и FF01 :: 1 соответственно)

Редактировать : У вас также есть ошибка на 2nd way, связанная с использованием вами итератора. Так как вы получаете новый .iterator() каждый раз в цикле for, вам повезло, что здесь нет бесконечного цикла. Я изменил ваш код на это, и он работает для меня:

$ cat Broadcasts.java 
import java.net.*;
import java.util.*;

public class Broadcasts
{
    public static void main(String[] args)
    {
        HashSet<InetAddress> listOfBroadcasts = new HashSet<InetAddress>();
        Enumeration list;
        try {
            list = NetworkInterface.getNetworkInterfaces();

            while(list.hasMoreElements()) {
                NetworkInterface iface = (NetworkInterface) list.nextElement();

                if(iface == null) continue;

                if(!iface.isLoopback() && iface.isUp()) {
                    //System.out.println("Found non-loopback, up interface:" + iface);

                    Iterator it = iface.getInterfaceAddresses().iterator();
                    while (it.hasNext()) {
                        InterfaceAddress address = (InterfaceAddress) it.next();
                        //System.out.println("Found address: " + address);
                        if(address == null) continue;
                        InetAddress broadcast = address.getBroadcast();
                        if(broadcast != null) 
                        {
                            System.out.println("Found broadcast: " + broadcast);
                            listOfBroadcasts.add(broadcast);
                        }
                    }
                }
            }
        } catch (SocketException ex) {
            System.err.println("Error while getting network interfaces");
            ex.printStackTrace();
        }

        // return listOfBroadcasts;
    }
}

Другая проблема, с которой вы можете столкнуться, - это попытка / отлов в основном функции whole , которая может привести к остановке этого кода, если он столкнется с чем-то неожиданным. Было бы лучше окружить возможные точки сбоя try / catch и сделать что-то вменяемое (например, пропустить интерфейс или адрес), но я не смотрел, какие методы могут генерировать исключения.

Редактировать 2 : Я неправильно прочитал ваш код; ваш итератор был в порядке. ;-) Проблема (на которую я указал ранее) заключалась в том, что ваш 1st way закорачивает ваш 2nd way; поскольку он попадает в оператор continue;, если первый адрес - null, вы даже не пытаетесь просмотреть их все.

В любом случае, запустите эти операторы println и опубликуйте результаты, если у вас все еще есть проблемы.

Редактировать 3 : ОК, я сдаюсь. ;-) Судя по выводу, который вы разместили, похоже, что вы столкнулись с ошибкой в ​​классе NetworkInterface.

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

Поскольку вы работаете в Linux, вы всегда можете прибегнуть к альтернативному подходу: выделять и вызывать что-то вроде:

/sbin/ip addr | perl -ne 'print "$1\n" if $_  =~ /inet.* brd ([0-9\.]*)/'

... который должен вернуть вам список адресов широковещания.

Редактировать 4 : Я только что заметил в JavaDoc для NetworkInterface есть вызов getSubInterfaces(). Может быть, вам нужно позвонить, чтобы убедиться, что вы получите все адреса? (может помочь опубликовать вывод /sbin/ip addr и /sbin/ifconfig)

Редактировать 5 : Относительно только что добавленной награды. (Этому вопросу больше года!) Может, кто-нибудь запустит код в моем ответе выше (отредактирован, чтобы его было легко скопировать / вставить / запустить) и скажите мне, работает ли он? Если это не так, отредактируйте вопрос и запишите точные ошибки / проблемы.

...