我有一个奇怪的要求,能够在linux机器上侦听来自Java的多个networking接口,并确定它们中的一个是否接收到某种types的UDP数据包。 我需要的输出数据是有问题的接口的IP地址。 有没有办法在Java中做到这一点?
听通配符地址(新的DatagramSocket(端口))没有帮助,因为虽然我得到广播数据包,我不能确定他们通过接口的本地IP地址。 绑定到某个接口(新的DatagramSocket(端口,地址))时监听广播根本不接收数据包。 这个案例值得一个代码示例,显示了我想要做的事情:
Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface ni = (NetworkInterface) interfaces.nextElement(); Enumeration addresses = ni.getInetAddresses(); while (addresses.hasMoreElements()) { InetAddress address = (InetAddress)addresses.nextElement(); if (address.isLoopbackAddress() || address instanceof Inet6Address) continue; //Not interested in loopback or ipv6 this time,thanks DatagramSocket socket = new DatagramSocket(PORT,address); //Try to read the broadcast messages from socket here } }
我也尝试着使用根据接口的真实IP开始构build的广播地址初始化套接字,其余的根据正确的networking掩码:
byte [] mask = { (byte)255,0 }; byte[] addrBytes = InetAddress.getByname(\”126.5.6.7\”).getAddress(); for (int i=0; i < 4; i++) { addrBytes[i] |= ((byte)0xFF) ^ mask[i]; } InetAddress bcastAddr = InetAddress.getByAddress(addrBytes);
这只是在构造DatagramSocket时抛出一个BindException。
如何在.NET中侦听windows广播消息?
所有接口上的UDP广播
如何在windows Vista中模拟/replace/重新启用古典混音器控件(或命令)?
linux上的快速用户空间进程间通知方法?
在Win32 SDK中使用PlaySound时,如何检测声音何时播放完毕?
编辑: BindException(java.net.BindException:无法分配请求的地址)调用DatagramSocket的广播地址(例如126.255.255.255)的构造函数只有最新的Ubuntu 9.04(可能不是Ubuntu,但内核版本特定的问题,但) 。 使用Ubuntu 8.10,这个工作,以及我正在处理的红帽发行版(RHEL 4.x)。
显然,绑定到某个本地IP时不接收数据包是正确的行为 ,尽pipe在windows中是有效的。 我需要在linux(RHEL和Ubuntu)上运行。 使用低级别的C代码有一个解决schemesetsockopt(SO_BINDTODEVICE),我无法在Java-API中find。 这并不完全让我爆发乐观,尽pipe:-)
如何用Delphi来播放单音或自定义波形?
如何允许windows 7接受来自地址为“127.0.0.2”的外部设备的UDP消息?
多播系统上的UDP广播
UDP广播接收问题与Ubuntu 9.04,但不是8.04
仅从特定适配器(例如192.168.101.1)发送UDP广播(255.255.255.255); 在windows上
最后,这是一个IPV6 linux内核问题。 通常我已经禁用IPV6,因为它会引起各种头痛。 然而,在Ubuntu 9.04中,禁用IPV6是非常困难的,我放弃了这一点,这让我有些失望。
要收听来自特定界面的广播消息,我将首先创建接口IP地址的“广播版本”:
byte [] mask = { (byte)255,0 }; byte[] addrBytes = InetAddress.getByname(\”126.5.6.7\”).getAddress(); for (int i=0; i < 4; i++) { addrBytes[i] |= ((byte)0xFF) ^ mask[i]; } InetAddress bcastAddr = InetAddress.getByAddress(addrBytes);
当然,如果许多接口都有一个以相同的网络部分开始的IP,那么这并不能真正将我与某个接口绑定,但是对于我来说,这个解决方案已经足够了。
然后我创建该地址(和所需的端口)datagramsocket,它的工作原理。 但不是没有将下列系统属性传递给JVM:
-Djava.net.preferIPv6Addresses=false -Djava.net.preferIPv4Stack=true
我不知道如何IPV6设法中断收听广播,但它确实,并上述参数修复它。
为了重申你的问题,你需要确定接收广播UDP数据包的接口。
如果绑定到通配符地址,则会收到广播,但无法确定接收数据包的网络地址。
如果绑定到特定的接口,则知道您正在接收哪个接口地址,但不再接收广播(至少在linux TCP / IP堆栈上)。
正如其他人所提到的,有一些Java的第三方原始套接字库,例如RockSaw或Jpcap ,它们可以帮助您确定实际接口的地址。
不知道这是否有帮助,但我知道要获得所有网络接口的列表:
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
也许你可以独立绑定到每一个?
刚刚发现了getNetworkInterfaces()的一些很好的例子。
http://www.javadocexamples.com/java/net/NetworkInterface/getNetworkInterfaces().HTML
据我所知,要做到这一点的唯一方法就是用这个方法
IP_RECVDSTADDR
套接字选项。 这个选项应该确保数据包的接口的dst地址在绑定到通配符地址时可用。 所以它应该与广播我也假设。
下面是我从互联网上找到的一个C例子:
如何获取传入数据包的UDP目标地址
我会阅读recvmsg ,然后尝试找出这个接口是否可用Java。
编辑:
我刚刚意识到,如果在Java中支持,可能还有一个选项。 您可能仍然需要IP_RECVDSTADDR套接字选项(不确定),但是可以使用原始套接字并从IP头获取目标地址,而不是使用recvmsg。
使用SOCK_RAW打开您的套接字,您将在每条消息的开始处获得完整的IP标头,包括源地址和目标地址。
下面是一个在linux上用C语言对原始套接字使用UDP的例子:
高级TCP / IP – 原始套接字程序示例
如果这种方法在Java中不起作用,我也会感到惊讶。
EDIT2
还有一个想法。 是否有一个原因,你不能使用多播或您选择了多播广播的特定原因? 据我所知Multicast,你总是知道接收数据包的接口,因为当你加入一个多播组时(特别是通过IP4,通过它的一个IP地址绑定到接口),你总是绑定到特定的接口。
不能发表评论,所以添加这个作为一个答案,而不是。
那很有意思。 虽然很好奇你为什么这样做
byte[] addrBytes = InetAddress.getByname(\”126.5.6.7\”).getAddress();
而不仅仅是
byte[] addrBytes = {126,5,6,7);
或者是接口地址以字符串的形式得到你?
总结
以上是内存溢出为你收集整理的Linux上的Java:侦听绑定本地地址上的广播消息全部内容,希望文章能够帮你解决Linux上的Java:侦听绑定本地地址上的广播消息所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
请登录后查看评论内容