在 Java 中检测所有可用网络的广播地址

2022-09-03 16:00:33

对于我的项目,我想获得所有可用广播地址的列表,以便我可以广播请求,并且位于未指定网络中其他计算机上的其他应用程序将响应并获取列表(现在使用带有Mike贡献的小修改版本)提出了以下结果:


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;
}

它适用于reqular LAN,但是当涉及到WiFi LAN时,它只是跳过了一个步骤后的第二个而循环,因为即使我曾经只是查看正在通过的接口,它也写了无线LAN的名称和我的IP对应于网络。addressSystem.out.println(interfaceItem)

编辑1:这是输出,其中172.16.1.104是我在无线网络中的IP。问题只出现在我带有Wifi的笔记本电脑上。输出来自我的笔记本电脑,我主要使用无线,有时我使用UTP与我的朋友联系。我的笔记本上还有一个VirtualBox的网络接口。

你能告诉我它有什么问题吗?谢谢!

注意:所以事实证明,这可能特别适合我的笔记本,代码通常适用于其他人,我喜欢这种问题:-)对我来说似乎是一个死胡同,但无论如何感谢帮助:-)

仍然爱你!;-)


答案 1

我认为您需要遍历所有地址,并另外检查广播地址是否也是如此。null

请注意,您可能还期望将地址分配给接口。在我的Linux系统上,使用您的代码,我看到的第一个地址是IPv6地址,具有空广播(因为没有IPv6广播这样的东西 - 尽管您可以使用多播来实现相同的效果)。

您需要完全删除代码部分。当您到达那里时,您将转到下一个界面,而不是考虑有两个地址的可能性。1st waycontinue;

您始终希望迭代所有可以进行广播的地址的另一个原因是,您需要考虑可能将两个网络上的地址分配给一个接口。例如,您可能有一个同时具有和已分配的接口。192.168.0.1/24172.16.0.1/24

此外,请考虑使用 来存储广播地址,以防止在同一子网上分配两个地址的情况。Set

最后,由于使用广播地址将限制您只能与在同一子网中具有 IP 地址的主机通信,因此您可能会错过未正确配置相同子网/网络掩码的主机。因此,您可能需要考虑为此使用多播;您可以使用 IPv4(或 IPv6)所有节点多播地址来访问子网上的所有主机,而不管配置的地址如何。(分别为 224.0.0.1 和 FF01::1)

编辑您在第二种方式上也有一个错误,与您使用迭代器有关。由于每次在 for 循环中你都会得到一个新的 .iterator(),所以你很幸运这里没有无限循环。我把你的代码改成了这个,它对我有用:

$ 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 way2nd waycontinue;null

在任何情况下,如果仍有问题,请使用这些语句运行并发布结果。println

编辑3:好的,我放弃了。;-)根据您发布的输出,看起来您在类中遇到了一个错误。NetworkInterface

我不知道关闭该选项是否会有所帮助,但您应该对其进行测试。我搜索了一下描述此行为的错误报告,但找不到任何错误报告。preferIPv4Stack

由于您使用的是Linux,因此您始终可以采用回退方法,即外壳并调用如下内容:

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

...这应该会返回广播地址列表。

编辑4:我刚刚注意到在JavaDoc for NetworkInterface中有一个调用。也许您需要调用它以确保您获得所有地址?(发布 和 的输出可能会有所帮助)getSubInterfaces()/sbin/ip addr/sbin/ifconfig)

编辑5:关于刚刚添加的赏金。(这个问题已经一年多了!有人可以在上面的答案中运行代码(编辑以使其易于复制/粘贴/运行)并告诉我它是否有效吗?如果没有,请编辑问题并记下确切的错误/问题。


答案 2

推荐