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

问题描述 投票:0回答:1

对于我的项目,我想要获取所有可用广播地址的列表,以便我可以广播请求,并且位于未指定网络中的其他计算机上的其他应用程序将响应并获取列表(现在使用稍微修改的版本,贡献为迈克)想出了这个:


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

它对于常规 LAN 工作得很好,但是当涉及到 WiFi LAN 时,它只是在一步后跳过第二个 while 循环,因为

address
等于 null,即使当我使用
System.out.println(interfaceItem)
只是为了查看哪些接口消失时通过它写下了无线局域网的名称和我的网络对应的IP。

编辑1: This 是输出,其中 172.16.1.104 是我在无线网络中的 IP。该问题仅出现在我的带有 Wifi 的笔记本上。输出来自我的笔记本,我主要使用无线,有时我使用 UTP 与我的朋友连接。我的笔记本上也有一个VirtualBox的网络接口。

你能告诉我这是怎么回事吗?谢谢!

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

依然爱你! ;-)

java networking broadcast
1个回答
5
投票

我认为您需要迭代所有地址,并另外检查广播地址是否为

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
上也有一个错误,与您对迭代器的使用有关。由于每次 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 基本上围绕 entire 函数,如果遇到意外情况,这将导致此代码停止。最好用 try/catch 包围可能的故障点并做一些理智的事情(例如跳过接口或地址),但我没有查看哪些方法可以抛出异常。

编辑2:我误读了你的代码;你的迭代器很好。 ;-) 问题(我之前指出过)是你的

1st way
使你的
2nd way
短路;因为它命中了
continue;
语句,如果第一个地址是
null
,你甚至不会尝试循环遍历它们。

无论如何,如果仍然遇到问题,请运行这些

println
语句并发布结果。

编辑3:好吧,我放弃了。 ;-) 根据您发布的输出,您似乎在

NetworkInterface
类中遇到了错误。

我不知道关闭

preferIPv4Stack
选项是否有帮助,但你应该测试一下。我搜索了一些描述此行为的错误报告,但找不到任何报告。

由于您使用的是 Linux,因此您始终可以采取后备方法,即 shell 并调用类似以下内容:

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

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

编辑 4:我刚刚注意到在 NetworkInterface 的 JavaDoc 中有一个

getSubInterfaces()
调用。也许您需要调用它以确保获得所有地址? (发布
/sbin/ip addr
/sbin/ifconfig
的输出可能会有所帮助)

© www.soinside.com 2019 - 2024. All rights reserved.