Frage

Ich habe eine etwas seltsame Anforderung der Lage sein, auf eine Reihe von Netzwerk-Schnittstellen von Java auf einem Linux-Rechner zu hören und bestimmen, ob einer von ihnen UDP-Pakete eines bestimmten Typs empfängt. Die Ausgangsdaten, die ich brauche, ist die IP-Adresse der Schnittstelle in Frage. Gibt es eine Möglichkeit, dies in Java zu tun?

Zuhören auf der Wildcard-Adresse (neue Datagram (Port)) nicht, da hilft, während ich die Broadcast-Pakete zu tun bekommen, kann ich die lokale IP-Adresse der Schnittstelle nicht bestimmen sie durchkam. Hören von Sendungen, während auf eine bestimmte Schnittstelle gebunden zu sein (neue Datagram (Port, Adresse)) nicht empfängt, die Pakete überhaupt. Dieser Fall verdient ein Codebeispiel, das zeigt, was ich versuche zu tun:

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

Ich habe auch versucht die Fassung mit der Broadcast-Adresse zu Beginn des realen IP der Schnittstelle und dem Rest konstruiert zu initialisieren Basis nach der richtigen netmask:

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

Das wirft nur eine BindException wenn die Datagram zu konstruieren.

EDIT: BindException (java.net.BindException: angeforderte Adresse kann nicht zuweisen) von Datagram Konstruktor mit einer Broadcast-Adresse aufrufen (zB 126.255.255.255) kommt nur mit der neuesten Ubuntu 9.04 (wahrscheinlich nicht Ubuntu, aber Kernel-Version spezifische Frage though). Mit Ubuntu 8.10 das funktionierte, sowie mit der Red Hat-Release (RHEL 4.x), mit denen ich zu tun.

Empfangen Offensichtlich nicht die Pakete während gebunden an einem bestimmten lokalen IP die , obwohl in den Fenstern das funktioniert. Ich brauche, um es arbeiten an Linux (RHEL und Ubuntu). Mit Low-Level-C-Code gibt es eine Abhilfe setsockopt (SO_BINDTODEVICE), die ich nicht in dem Java-APIs finden. Diese nicht genau machen mich optimistisch platzen aber: -)

War es hilfreich?

Lösung

Dies war eine IPV6 Linux-Kernel-Ausgabe am Ende. Normalerweise habe ich deaktiviert IPV6, weil es alle Arten von Kopfschmerzen verursacht. Doch in Ubuntu 9.04 ist es so schwer, IPV6 zu deaktivieren, die ich aufgegeben, und das hat mich gebissen.

So hören Nachrichten von einer bestimmten Schnittstelle zu übertragen, werde ich zuerst die „Broadcast Version“ erstelle der IP-Adresse der Schnittstelle:

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

Zugegeben, ist dies wirklich binden mich nicht an eine bestimmte Schnittstelle, wenn viele Schnittstellen eine IP haben, die mit dem gleichen Netzwerkteil beginnt, aber für mich ist diese Lösung aus.

Dann erstelle ich die Datagram mit dieser Adresse (und dem gewünscht Port), und es funktioniert. Aber nicht ohne die folgenden Systemeigenschaften auf die JVM übergeben:

-Djava.net.preferIPv6Addresses=false -Djava.net.preferIPv4Stack=true 

Ich habe keine Ahnung, wie IPV6 hören Sendungen zu brechen schafft, aber es funktioniert, und die oben genannten Parameter zu beheben.

Andere Tipps

Ihr Problem neu zu formulieren, müssen Sie bestimmen, welche Schnittstelle übertragen UDP-Pakete empfangen wurden.

  • Wenn Sie die Wildcard-Adresse binden erhalten Sie die Sendungen, aber es gibt keine Möglichkeit, die Netzwerkadresse zu bestimmen, wurde das Paket empfangen auf.
  • Wenn Sie auf eine bestimmte Schnittstelle binden Sie wissen, welche Schnittstelle Adresse, die Sie erhalten, aber nicht mehr die Sendungen empfangen (zumindest auf dem Linux-TCP / IP-Stack.).

Wie andere erwähnt haben, gibt es Dritten Raw Sockets-Bibliotheken für Java wie Rocksaw oder Jpcap , mit dem Sie die Adresse bestimmen kann helfen, die eigentliche Schnittstelle.

Nicht sicher, ob das hilft, aber ich weiß, dass eine Liste aller Netzwerkschnittstellen zu bekommen:

Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();

Vielleicht können Sie zu jedem binden unabhängig?

Just fand einige großartige Beispiele für die Verwendung von getNetworkInterfaces ().

Nach bestem Wissen und Gewissen, den einzigen Weg, dies zu tun mit dem

sein würde,

IP_RECVDSTADDR

Socket-Option. Diese Option soll sicherstellen, dass die dst-Adresse der Schnittstelle das Paket kam auf zur Verfügung, wenn auf die Wildcard-Adresse gebunden. So soll es auch mit Broadcast arbeitet Ich gehe davon aus.

Hier ist ein C Beispiel, das ich aus dem Internet abgeholt:

Wie UDP Ziel gelangen Adresse auf eingehende Pakete

Ich lese würde auf recvmsg und dann versuchen und herausfinden, ob diese Schnittstelle ist in Java zur Verfügung.

Edit:

Ich habe erkannt, dass Sie eine weitere Option haben können, wenn sie in Java unterstützt wird. Unter Umständen müssen Sie noch die IP_RECVDSTADDR Socket-Option (nicht sicher), sondern recvmsg verwenden könnten Sie eine Raw-Socket verwenden und die Zieladresse aus dem IP-Header erhalten.

öffnen Sie die Buchse als mit SOCK_RAW und Sie werden die vollständigen IP-Header am Anfang jeder Nachricht einschließlich Quell- und Zieladressen erhalten.

Hier ist ein Beispiel für die Verwendung UDP mit einem Raw-Socket in C unter Linux:

Erweiterte TCP / IP - das RAW-STECKProgrammBeispiele

Ich wäre überrascht, wenn diese Methode in Java nicht funktioniert auch.

EDIT2

Eine weitere Idee. Gibt es einen Grund, warum Sie nicht Multicast oder einen bestimmten Grund verwenden, können Sie Multicast chose ausgestrahlt? Soweit ich mit Multicast verstehen würden Sie immer wissen, welche Schnittstelle die Pakete empfangen am, da Sie immer auf eine bestimmte Schnittstelle binden, wenn eine Multicast-Gruppe beitreten (vor allem mit IP4, wo man über eine von ihm an die Schnittstelle binden ist IP-Adressen).

Kann nicht kommentieren, so dass das Hinzufügen dieser als Antwort statt.

Das ist interessant. Obwohl bin neugierig, warum Sie tun,

byte[] addrBytes = InetAddress.getByName("126.5.6.7").getAddress();

anstatt nur

byte[] addrBytes = {126, 5, 6, 7);

oder ist es, dass die Interface-Adressen für Sie als String bekommen?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top