Ответ 1
Я думаю, вам нужно будет перебирать все адреса и дополнительно проверить, есть ли широковещательный адрес 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;
}
}
Еще одна проблема, с которой вы можете столкнуться, - это try/catch вокруг основной функции, которая заставит этот код остановиться, если он ударит что-то неожиданное. Было бы лучше окружить возможные точки отказа с помощью 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. Что касается только что добавленной награды. (Этот вопрос старше года!) Может кто-нибудь, пожалуйста, запустите код в моем ответе выше (отредактировано, чтобы было легко скопировать/вставить/запустить) и сказать, работает ли он? Если это не так, отредактируйте этот вопрос и обратите внимание на точные ошибки/проблемы.