Linux マシン上の Java から多数のネットワーク インターフェイスをリッスンし、そのうちの 1 つが特定のタイプの UDP パケットを受信するかどうかを判断できるという、やや奇妙な要件があります。必要な出力データは、問題のインターフェイスの IP アドレスです。Javaでこれを行う方法はありますか?
ワイルドカード アドレス (new DatagramSocket(port)) をリッスンしても役に立ちません。ブロードキャスト パケットを取得している間は、パケットが通過したインターフェイスのローカル IP アドレスを特定できないためです。特定のインターフェース (new DatagramSocket(port, address)) にバインドされている間にブロードキャストをリッスンすると、パケットがまったく受信されません。このケースは、私がやろうとしていることを示すコード例に値します:
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 の先頭に基づいて構築されたブロードキャスト アドレスでソケットを初期化し、残りは正しいネットマスクに従って初期化しようとしました。
byte [] mask = { (byte)255, 0, 0, 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 をスローするだけです。
EDIT:ブロードキャストアドレス(例:126.255.255.255)でDatagramSocketのコンストラクターを呼び出すことによるBindException(java.net.BindException:要求されたアドレスを割り当てることができません)は、最新のUbuntu 9.04にのみ付属しています(おそらくUbuntuではなく、カーネルバージョン固有の問題です) . これは Ubuntu 8.10 で機能し、私が扱っている Red Hat リリース (RHEL 4.x) でも機能しました。
Windowsではこれは機能しますが、特定のローカルIPにバインドされている間にパケットを受信しないことは明らかに正しい動作です。Linux (RHEL および Ubuntu) で動作させる必要があります。低レベルの C コードには、Java API では見つからない回避策の setsockopt(SO_BINDTODEVICE) があります。しかし、これは私を楽観的に爆発させるわけではありません:-)