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

发布于 2024-10-15 21:00:20 字数 1875 浏览 2 评论 0 原文

对于我的项目,我想获取所有可用广播地址的列表,以便我可以广播请求,并且位于未指定网络中其他计算机上的其他应用程序将响应并获取列表(现在使用由 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;
}

它对于常规 LAN 工作得很好,但是当涉及到 WiFi LAN 时,它只是在一步后跳过第二个 while 循环,因为 address 等于 null,即使当我使用 < code>System.out.println(interfaceItem) 只是为了查看正在通过哪些接口,它写下了无线 LAN 的名称和与该网络对应的 IP。

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

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

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

仍然爱你! ;-)

For my project I wanted to get a list of all available broadcast addresses so I could broadcast a request and my other application located on other computer in the unspecified network would respond and to get the list I (now using little modified version with contribution of Mike) came up with this:


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

It works quite well for reqular LAN however when it comes to the WiFi LAN it just skips the second while loop after one step because of having address equals null even though when I used System.out.println(interfaceItem) just to view what interfaces are being gone through it wrote wireless LAN's name and my IP corresponding to the network.

EDIT 1:
This is the output where 172.16.1.104 is my IP in the wireless network. The problem appears ONLY on my notebook with Wifi. The output is from my notebook where I mostly use wireless and sometimes I use UTP to connect with my friend. There is also one network interface of VirtualBox on my notebook.

Could you tell me what's wrong with it? Thank you!

Note: So it turns out that this might be problem for my notebook in particular and the code works for everybody else in general, I love this kind of problem :-) Seems like a dead end to me but thank for help anyway :-)

Still love you! ;-)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

太阳公公是暖光 2024-10-22 21:00:20

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

请考虑您可能也有不希望分配给接口的地址。在我的 Linux 系统上,使用您的代码,我看到的第一个地址是 IPv6 地址,具有空广播(因为不存在 IPv6 广播之类的东西 - 尽管您可以使用多播来达到相同的效果)。

您需要完全删除代码的 1st way 部分。当您继续;时,您将进入下一个界面,而不是考虑有两个地址的可能性。

您总是想要迭代所有可以进行广播的地址的另一个原因是您需要考虑可能在分配给一个接口的两个网络上有地址。例如,您的接口可能同时分配了 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:我误读了你的代码;你的迭代器很好。 ;-) 问题(我之前指出过)是你的第一种方式使你的第二种方式短路;因为它命中了 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 的输出可能会有所帮助)

I think you'll need to iterate across all the addresses, and additionally check if the broadcast address is null as well.

Consider that you might have addresses that you aren't expecting assigned to the interface as well. On my Linux system, with your code, the first address I see is an IPv6 address, with a null broadcast (since there is no such thing as an IPv6 broadcast - though you can use multicast to achieve the same effect).

You need to completely remove the 1st way section of the code. When you continue; there you'll go to the next interface instead of considering the possibility that there are two addresses.

The other reason why you always want to iterate all the addresses that can have broadcasts is that you need to consider that you might have addresses on two networks assigned to an interface. For example, you might have an interface with both 192.168.0.1/24 and 172.16.0.1/24 assigned.

Also, consider using a Set to store the broadcast addresses to protect against the case where you might have two addresses on the same subnet assigned.

Finally, since using broadcast addresses will restrict you to talking only to hosts that have an IP address in the same subnet, you might miss hosts that are not configured properly with the same subnet/netmask. So you might want to consider using multicast for this; you could use the IPv4 (or IPv6) all nodes multicast addresses to reach all hosts on the subnet, regardless of the configured address. (224.0.0.1 and FF01::1, respectively)

Edit: You also have a bug on the 2nd way, related to your use of the iterator. Since you're getting a new .iterator() each time around the for loop, you're lucky there isn't an infinite loop here. I changed your code to this, and it works for me:

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

Another problem you may run into is the try/catch around basically the entire function, which would cause this code to stop if it hit something unexpected. It would be better to surround possible failure points with a try/catch and do something sane (like skip the interface or address), but I didn't look at which methods can throw exceptions.

Edit 2: I misread your code; your iterator was fine. ;-) The problem (which I pointed out earlier) was that your 1st way is short-circuiting your 2nd way; since it hits the continue; statement, if the first address is null you don't even try to loop through them all.

In any case, run with those println statements and post the results if you're still having trouble.

Edit 3: OK, I give up. ;-) Based on the output you posted, it looks like you are running into a bug in the NetworkInterface class.

I don't know if it would help to turn off the preferIPv4Stack option, but you should test that. I searched around a little bit for bug reports that describe this behavior and could not find any.

Since you're on Linux, you could always take the fallback approach of shelling out and calling something like:

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

... which should return you a list of broadcast addresses.

Edit 4: I just noticed in the JavaDoc for NetworkInterface there is a getSubInterfaces() call. Maybe you need to call this to make sure you get all the addresses? (it might help to post the output of /sbin/ip addr and /sbin/ifconfig)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文