Socket Status von UDP-Port prüfen (PortUnreachableException funktioniert nicht?)

JavaDevOp

Mitglied
Ich schreibe ein Programm, das prüfen soll, ob bestimmte UDP-Ports "offen" sind.

Mir ist klar, dass UDP ein verbindungsloses Protokoll ist, d.h. im Unterschied zu TCP findet bei UDP kein Verbindungsaufbau statt, sondern es werden einfach einzelne Pakete geschickt. Das bedeutet, wenn ich testweise ein Paket an einen UDP-Port schicke und der Ziel-Port ist tatsächlich "offen", d.h. ein Programm lauscht auf diesem Port, dann werde ich i.d.R. keine Antwort bekommen. Denn das Programm wird meine Test-Nachricht nicht verstehen und einfach ignorieren. Der interessantere Fall ist der, wenn der UDP-Port "geschlossen" ist, d.h. wenn auf dem Ziel-Port kein Programm lauscht. In diesem Fall verweigert der Host die Annahme des UDP-Pakets und signalisiert das an den Absender, mit einem ICMP-Paket mit Code 3 ("Port Unreachable"). Der Java-Socket wirft in diesem Fall eine PortUnreachableException, so dass wir erkennen können, dass der Port "geschlossen" ist.

So zumindest die Theorie:

6.5 ICMP Port Unreachable Error
[...]
One rule of UDP is that if it receives a UDP datagram and the destination port does not correspond to a port that some process has in use, UDP responds with an ICMP port unreachable [Code 3]. We can force a port unreachable using the TFTP client. The well-known UDP port for the TFTP server to be reading from is 69. But most TFTP client programs allow us to specify a different port using the connect command. We use this to specify a port of 8888. [...] An ICMP port unreachable is immediately returned. — http://isp.vsi.ru/library/Networking/TCPIPIllustrated/icmp_int.htm#6_5
Class PortUnreachableException
Signals that an ICMP Port Unreachable message has been received on a connected datagram.

Leider scheint das bei mir überhaupt nicht zu klappen! Ich bekomme immer nach längerer Zeit eine SocketTimeoutException, aber niemals eine PortUnreachableException, auch wenn der Ziel-Port mit 100% Sicherheit definitiv "geschlossen" ist. Habe es bereits mit verschiedenen Rechnern, sowohl im Internet als auch im lokalen Netz versucht. Im lokalen Netz weiß ich zu 100%, dass weder mein UDP-Anfrage-Paket noch das ICMP-Antwort-Paket irgenwie "gefilter" werden können. Die Rechner sind ja direkt über ein lokales Switch verbunden, d.h. da ist keine Firewall oder irgendwas in der Art dazwischen. Es ist auch keine Software-Firewall oder so installiert. Trotzdem konnte bisher nie eine PortUnreachableException von dem Java-Socket bekommen. Werde langsam etwas wahnsinnig damit. Was mach ich falsch? Oder ist das vielleicht ein bekannter Bug in Java? 🙄

Mein Code sieht so aus:
Java:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.HexFormat;

public class UdpTester {

    private static final HexFormat hexfmt = HexFormat.of();

    public static void main(final String[] args) {
        final InetAddress address;
        try {
            address = InetAddress.getByName("www.example.com");
            System.err.println("Address: " + address);
        } catch (UnknownHostException e) {
            System.err.println("Failed to resovle hostname: " + e.toString());
            return;
        }

        for (int port = 1; port <= 1024; ++port ) {
            try {
                testUdpPort(address, port);
            } catch(final IOException e) {
                System.err.printf("Error while testing port %d: %s%n", port, e.toString());
            }
        }
    }

    private static void testUdpPort(final InetAddress address, final int port) throws IOException {
        final DatagramSocket udpSocket = new DatagramSocket();
        try {
            udpSocket.setSoTimeout(30000);

            // Send packet
            try {
                final byte[] message = "hello".getBytes(StandardCharsets.ISO_8859_1);
                final DatagramPacket outbound = new DatagramPacket(message, message.length, address, port);
                udpSocket.send(outbound);
            } catch (final SocketTimeoutException e) {
                System.err.printf("Error while sending to port %d: %s%n", port, e.toString());
            }

            // Receive response
            try {
                final byte[] recvBuffer = new byte[65535];
                final DatagramPacket inbound = new DatagramPacket(recvBuffer, recvBuffer.length);
                udpSocket.receive(inbound); // <-- this shall throw PortUnreachableException, if the target port is closed !!!
                System.err.println("Response: " + hexfmt.formatHex(inbound.getData(), 0, inbound.getLength()));
            } catch (final SocketTimeoutException e) {
                System.err.printf("Error while receiving from port %d: %s%n", port, e.toString());
            }
        } finally {
            try {
                udpSocket.close();
            } catch(Exception e) { }
        }
    }
}

Ausgabe:
Code:
Address: www.example.com/93.184.216.34
Error while receiving from port 1: java.net.SocketTimeoutException: Receive timed out
Error while receiving from port 2: java.net.SocketTimeoutException: Receive timed out
Error while receiving from port 3: java.net.SocketTimeoutException: Receive timed out
Error while receiving from port 4: java.net.SocketTimeoutException: Receive timed out
Error while receiving from port 5: java.net.SocketTimeoutException: Receive timed out
Error while receiving from port 6: java.net.SocketTimeoutException: Receive timed out
Error while receiving from port 7: java.net.SocketTimeoutException: Receive timed out
Error while receiving from port 8: java.net.SocketTimeoutException: Receive timed out

Danke für Eure Hilfe!
 
Zuletzt bearbeitet:
Im RFC steht may:
If, in the destination host, the IP module cannot deliver the
datagram because the indicated protocol module or process port is
not active, the destination host may send a destination
unreachable message to the source host.
Ich will nicht ausschließen, dass viele Network Stacks /OS das einfach nicht mehr senden, weil man darüber relativ einfach Denial of Service machen kann, indem man mit Fake IP Adressen solche ICMP Nachrichten erzeugt.
 
Ich denke, mit der RFC ist man einfach viel zu low Level - das wird doch erst einmal aus Java Sicht nicht interessieren.

Was passiert denn, wenn Java dieses send aufruf? Das UDP Paket wird an den Netzwerk-Stack übergeben und damit ist das send schon beendet. Es wird also nicht auf irgend eine Antwort vom Zielsystem gewartet. Daher kann es keine Exception geben, die irgend eine ICMP Antwort auswertet.

Also aus der JavaDoc (DatagramSocket (Java SE 17 & JDK 17) (oracle.com)):
PortUnreachableException - may be thrown if the socket is connected to a currently unreachable destination. Note, there is no guarantee that the exception will be thrown.
Das klingt erst einmal danach, dass diese Exception nur geworfen werden könnte, wenn das Ziel nicht erreichbar ist.

Das hat also - nach meinem Verständnis - nichts mit dem Status auf dem Zielrechner zu tun sondern nur mit dem Routing auf deinem Rechner. Sprich: Das Paket gibt das UDP Paket an den Netzwerk-Stack und da kann direkt zurück kommen: Sorry - das Ziel ist nicht erreichbar.

Somit ist das eine Auswertung, die erst nach dem send kommen kann. So wie Du auf eine udp Antwort hörst könnte man theoretisch eine icmp Antwort abfrage. Nur das ist von Java nicht unterstützt / zu "low level".

Das wäre zumindest mein Verständnis von der Thematik. Aber ich habe mich da mit udp Verbindungen nicht zu intensiv beschäftigt - ich kenne das nur so von der administrativen Seite her.
 
Danke für die Antwoten!

Was passiert denn, wenn Java dieses send aufruf? Das UDP Paket wird an den Netzwerk-Stack übergeben und damit ist das send schon beendet. Es wird also nicht auf irgend eine Antwort vom Zielsystem gewartet. Daher kann es keine Exception geben, die irgend eine ICMP Antwort auswertet.
Somit ist das eine Auswertung, die erst nach dem send kommen kann. So wie Du auf eine udp Antwort hörst könnte man theoretisch eine icmp Antwort abfrage. Nur das ist von Java nicht unterstützt / zu "low level".
Ja, richtig, bei dem ersten send() auf einem "frischen" Socket kann man keine PortUnreachableException erwarten.

Aber die PortUnreachableException müsste spätestens dann ausgelöst werden, wenn man ein weiteres send() auf dem selben Socket versucht, nachdem bereits ein "ICMP Port Unreachable" für ein vorangegangenes send() auf diesem Socket eingetroffen ist. Das selbe gilt auch für den Fall dass das "ICMP Port Unreachable" eintrifft, während man mittels receive() auf eine mögliche Antwort wartet...

PortUnreachableException ist aus diesem Grund auch bei receive() dokumentiert.

Ich habe versucht statt dem receive() eine Schleife von mehreren send()s auszuführen, oder nach dem receive()-Timeout noch ein weiteres send() auszuführen. Ändert aber auch nichts daran, dass ich keine PortUnreachableException bekomme.

Also aus der JavaDoc (DatagramSocket (Java SE 17 & JDK 17) (oracle.com)):

Das klingt erst einmal danach, dass diese Exception nur geworfen werden könnte, wenn das Ziel nicht erreichbar ist.

Das hat also - nach meinem Verständnis - nichts mit dem Status auf dem Zielrechner zu tun sondern nur mit dem Routing auf deinem Rechner. Sprich: Das Paket gibt das UDP Paket an den Netzwerk-Stack und da kann direkt zurück kommen: Sorry - das Ziel ist nicht erreichbar.
Ich denke die PortUnreachableException bezieht sich explizit auf die "ICMP Port Unreachable" Nachricht, welche ja besagt, dass auf dem Ziel-UDP-Port aktuell keine Anwendung erreichbar ist, d.h. der Port ist geschlossen.

Die "ICMP Port Unreachable" Nachricht ist quasi das gegenstück zu "TCP RST" (d.h. "Connection Refused") bei TCP.

Es gibt auch sowas wie "ICMP Network Unreachable" und "ICMP Host Unreachable" Nachrichten, für die Fälle, dass das Netzwerk bzw. der Host nicht erreichbar ist. Das hat aber meines Erachtens dann nichts mit der PortUnreachableException zu tun.

BTW: Ich habe durchaus bereits ConnectExceptions oder SocketExceptions mit dem Inhalt "no route to host", "host unreachable", "address not available" oder "network is unreachable" erhalten, z.B. wenn die Internetverbindung streikt.

LimDul hat gesagt.:
Ich will nicht ausschließen, dass viele Network Stacks /OS das einfach nicht mehr senden, weil man darüber relativ einfach Denial of Service machen kann, indem man mit Fake IP Adressen solche ICMP Nachrichten erzeugt.

Hmm, könnte sein. Aber das würde ich dann eher bei "öffentlichen" Servern im Internet erwarten, die hinter einer Firewall stehen. Bei meinem lokalen Linux-Server bekomme ich definitiv ebenfalls keine PortUnreachableExceptions auf den UDP-Ports, die ganz sicher geschlossen sind. Und hier kann ich, wie schon gesagt, ausschließen, dass ICMP-Nachrichten gefiltert/geblockt werden.

BTW: Man findet im Netz Anleitungen, wie man unter Linux das Versenden von "ICMP Unreachable" Pakete per ip-tables Regeln blocken kann. Bedeutet für mich, dass per Default solche Nachrichten vom System verschickt werden, sonst wäre das ja gar nicht notwendig.
 
Zuletzt bearbeitet:
Mit einem send wird doch auch kein ICMP Paket verschickt.
Dann schaue dir doch mal den IP Header an bei dem UDP Paket.
Und schaue wie ein IP Header Netzwerkschicht 3 aussehen muss damit es ein ICMP ist.


Du erwartest eine Antwort auf eine ICMP anfrage die du gar nicht gemacht hast.
 
Dann würde ich Dir einfach einmal empfehlen, den ganzen Traffic mitzuschneiden. Dann kannst Du ja genau schauen, was für Pakete alle versendet werden. Sprich: Du siehst dann das udp Paket,, das kommt und ggf. ausgehende icmp Pakete.

Dann hättest Du erst einmal ein Überblick, was real auf dem Netzwerk passiert. Das wäre eine gute Grundlage für weitere Schritte / Tests, wobei ich da dann ggf. auch von Java auf C / C++ oder Rust wechseln würde, um auf niedrigerem Level die Vorgänge zu implementieren.

Damit würdest Du verhindern, dass Du nur mit irgendwelchen Dokumentationen (RFCs) arbeitest, was evtl. wie funktionieren könnte um dann auf dem hohen Level "Java" irgendwas erkennen zu wollen.
 
Mit einem send wird doch auch kein ICMP Paket verschickt.
Dann schaue dir doch mal den IP Header an bei dem UDP Paket.
Und schaue wie ein IP Header Netzwerkschicht 3 aussehen muss damit es ein ICMP ist.

Du erwartest eine Antwort auf eine ICMP anfrage die du gar nicht gemacht hast.
Ich denke da liegt ein Missverständnis vor: ICMP wird benutzt, damit Server oder auch Netzwerk-Komponenten (z.B. Router) bestimmte Zustands-Informationen oder Fehler-Codes zurück melden können. Dem geht normalerweise keine ICMP-Anfrage voraus – wenn es so etwas wie eine "ICMP-Anfrage" überhaupt gibt. Mir fällt da außer bei "Echo" eigentlich keine Fall ein, wo ICMP in beide Richtungen geht 🤔

Bei UDP ist es so festgelegt, dass wenn Du ein UDP-Paket an einen "geschlossenen" Port sendest, also an einen Port auf dem aktuell gar keine Anwendung lauscht, dann signalisiert der Server bzw. das Betriebssystem das, indem ein ICMP-Paket vom Typ 3 ("Unreachable") und mit dem Code 3 ("Destination port unreachable") zurück geschickt wird. Spziell ür den Fall gibt es die PortUnreachableException.

public class PortUnreachableException extends SocketException

Signals that an ICMP Port Unreachable message has been received on a connected datagram.
public void send(DatagramPacket p) throws IOException
public void receive(DatagramPacket p) throws IOException


Throws:
[...]
PortUnreachableException
 
Zuletzt bearbeitet:
Klingt interessant. Aber wie mache ich das mit Java am besten? 😵
Java bietet nur einen High Level Socket - daher ja explizit die Aussage, dass man eben auf niedrigerem Level ansetzt.

Und da wäre dann ein Monitoring Tool wie wireshark die einfachste Lösung. Aber man kann auch direkt auf tcpdump oder so aufsetzen - dann bekommt man halt wirklich nur den dump und hat erst einmal keine Oberfläche die einem Dinge auch direkt auswertet und so.
 
Okay, hab jetzt einfach mal Wireshark mitlaufen lassen. Das ging überraschend einfach 😉

Musste nur noch herausfinden, wie man die relevanten Zeilen herausfiltert. Sieht aber alles wie erwartet aus, denke ich:



Es kommt also für jedes UDP-Paket ein entsprechendes ICMP "Destination unreachable (Port unreachable)" zurück.

Java scheint das aber nicht zu interessieren... 😠
 
Sicher, dass die Firewall des Zielsystems ICMP-Pakete nicht einfach nicht zulässt? 😉 Genau dann tritt nämlich beschriebenes Verhalten ein, d. h. du bekommst weder ein "Ja, ist (halb-)offen" noch ein "Nein, ist nicht offen". 😀
 
Zuletzt bearbeitet:
Evtl. kann Java die Rückmeldung der Anfrage nicht zuordnen. Fire & Forget.

Hast du ein Akutes Problem oder möchtest du nur wissen, warum die Rückmeldung nicht erkannt wird?
 
Dann ist ein Fehler in der Java-Doc...
Oder man sollte die Dokumentation einfach einmal etwas genauer lesen...

Das Problem ist, dass kein connect Aufruf gemacht wurde. Damit kann der Socket für beliebige Ziele verwendet werden. Damit werden ICMP Rückmeldungen nicht ausgewertet.

Die Beschreibung von connect besagt halt, dass bei ICMP destination unreachable Paketen nachfolgende Aufrufe zu send und receive eine PortUnreachableException auslösen:
Connects the socket to a remote address for this socket. When a socket is connected to a remote address, packets may only be sent to or received from that address. By default a datagram socket is not connected. If the socket is already closed, then this method has no effect.
If this socket is not bound then this method will first cause the socket to be bound to an address that is assigned automatically, as if invoking the bind method with a parameter of null. If the remote destination to which the socket is connected does not exist, or is otherwise unreachable, and if an ICMP destination unreachable packet has been received for that address, then a subsequent call to send or receive may throw a PortUnreachableException. Note, there is no guarantee that the exception will be thrown.
 
Das Problem ist, dass kein connect Aufruf gemacht wurde. Damit kann der Socket für beliebige Ziele verwendet werden. Damit werden ICMP Rückmeldungen nicht ausgewertet.

Die Beschreibung von connect besagt halt, dass bei ICMP destination unreachable Paketen nachfolgende Aufrufe zu send und receive eine PortUnreachableException auslösen:

Dass man bei UDP überhaupt connect() aufrufen kann/soll verwirrt mich 🤯

Es ändert aber leider auch nichts:
Java:
public static void main(String[] args) throws Exception {
    final InetAddress address = InetAddress.getByName("192.168.2.202");
    for (int port = 12345; port < 13345; ++port) {
        final DatagramSocket udpSocket = new DatagramSocket();
        try {
            udpSocket.setSoTimeout(10000);
            udpSocket.connect(address, port); // <-- neu hinzugefügt !!!
            for (int retry = 0; retry < 3; ++retry) {
                try {
                    final byte[] message = "hello".getBytes(StandardCharsets.US_ASCII);
                    udpSocket.send(new DatagramPacket(message, message.length, address, port));
                    final byte buffer[] = new byte[1024];
                    udpSocket.receive(new DatagramPacket(buffer, buffer.length));
                } catch(Exception e) {
                    System.err.printf("Error while trying port %d: %s%n", port, e.toString());
                }
            }
        } finally {
            try {
                udpSocket.close();
            } catch (Exception e2) { }
        }
    }
}

Bekomme nach wie vor immer nur java.net.SocketTimeoutException: Receive timed out Exceptions 😢
 
Nö, "may receive" bedeutet nicht, dass die Funktionalität überhaupt nicht implementiert wurde, wie hier aber suggeriert wird.
Bitte den ganzen Post lesen und nicht nur Teile heraus picken. Ich habe doch ganz deutlich die Dokumentation von connect() beschrieben und dort findet es sich.

Und Du hast selbst einen SO Beitrag verlinkt, der eben genau das Gleiche zitiert...

Aber ich denke, hier handelt es sich einfach um unseren Forentroll Tobias, richtig?

Dass man bei UDP überhaupt connect() aufrufen kann/soll verwirrt mich 🤯
Das geht halt generell - das ist in dem SO Link, der inzwischen verlinkt wurde, auch beschrieben. Dabei geht es halt nicht um einen Verbindungsaufbau wie bei tcp/ip Verbindungen sondern um eine Festlegung, welches Ziel der Socket haben soll. Dadurch können die zurückkehrenden ICMP Meldungen zugeordnet werden.

Es ändert aber leider auch nichts
Das dürfte daran liegen, dass der receive Aufruf erfolgt, ehe die ICMP Antwort verarbeitet werden konnte. Bau da einfach mal ein Sleep dazwischen von 1000ms oder so. Ohne den Code / die implementierung geprüft zu haben, gehe ich davon aus, dass es einfach ein einmaliger Statuscheck ist und ein eingehendes ICMP Paket keinen IO-Lock löst.
 
Soweit ich das verstehe, schreibt er da, dass er eine PortUnreachableException bekommt "if the remote socket is not listening", also wenn der Ziel-Port "geschlossen" ist und der Server dementsprechend eine "Port Unreachable" ICMP-Nachricht sichickt.

Genau so soll es ja aber auch sein!

Mein Problem ist gerade, dass ich keine PortUnreachableException bekomme, in dem Fall in dem es aber eigentlich so sein müsste 😏

(ich habe bereits per Wireshark verifiziert, dass die Gegenseite sehr wohl "Port Unreachable" ICMP-Nachrichten schick)
 
Das Problem ist aber doch die Zuordnung. Wenn Du die Dokumentation zu der Exception anschaust, dann findest Du auch explizit:
Signals that an ICMP Port Unreachable message has been received on a connected datagram.

Ein connect ist also notwendig. Und dann besagt die Dokumentation, dass nach dem Empfang einer ICMP Port Unreachable message nachfolgende send und receive Aufrufe die Exception werfen. Die Reihenfolge ist also wichtig.
"and if an ICMP destination unreachable packet has been received for that address, then a subsequent call to send or receive may throw a PortUnreachableException. Note, there is no guarantee that the exception will be thrown."

Daher meine Bitte, es noch einmal mit einem Thread.sleep zwischen dem send und dem receive zu versuchen.
 
Das dürfte daran liegen, dass der receive Aufruf erfolgt, ehe die ICMP Antwort verarbeitet werden konnte. Bau da einfach mal ein Sleep dazwischen von 1000ms oder so. Ohne den Code / die implementierung geprüft zu haben, gehe ich davon aus, dass es einfach ein einmaliger Statuscheck ist und ein eingehendes ICMP Paket keinen IO-Lock löst.
Das Problem ist aber doch die Zuordnung. Wenn Du die Dokumentation zu der Exception anschaust, dann findest Du auch explizit:
Signals that an ICMP Port Unreachable message has been received on a connected datagram.

Ein connect ist also notwendig. Und dann besagt die Dokumentation, dass nach dem Empfang einer ICMP Port Unreachable message nachfolgende send und receive Aufrufe die Exception werfen. Die Reihenfolge ist also wichtig.
"and if an ICMP destination unreachable packet has been received for that address, then a subsequent call to send or receive may throw a PortUnreachableException. Note, there is no guarantee that the exception will be thrown."

Daher meine Bitte, es noch einmal mit einem Thread.sleep zwischen dem send und dem receive zu versuchen.

Dafür hatte ich eigentlich bereits die innere Schleife eingeabaut, die drei Mal hintereinander das send() und receive() ausführt. Und zwar auf der selben DatagramSocket-Instanz, auf welcher nun auch noch zusätzlich zu aller erst ein connect() aufgerufen wurde. Da das receive() jedes mal 10 Sec "hängt", bis man die SocketTimeoutException bekommt, müsste also mehr als genau Zeit vergangen sein.

Klappt irgendwie trotzdem nicht...
 
Zur Sicherheit, diese Version produziert immer noch lediglich eine SocketTimeoutException beim receive():
Java:
final DatagramSocket udpSocket = new DatagramSocket();
try {
    udpSocket.setSoTimeout(10000);
    udpSocket.connect(address, port);

    try {
        final byte[] message = "hello".getBytes(StandardCharsets.US_ASCII);
        udpSocket.send(new DatagramPacket(message, message.length, address, port));
    } catch(final IOException e) {
        System.err.printf("Error while testing port %d: %s%n", port, e.toString());
    }

    Thread.sleep(5000);

    try {
        final byte[] message = "hello".getBytes(StandardCharsets.US_ASCII);
        udpSocket.send(new DatagramPacket(message, message.length, address, port));
    } catch(final IOException e) {
        System.err.printf("Error while testing port %d: %s%n", port, e.toString());
    }

    Thread.sleep(5000);

    try {
        final byte buffer[] = new byte[1024];
        udpSocket.receive(new DatagramPacket(buffer, buffer.length));
    } catch(final IOException e) {
        System.err.printf("Error while testing port %d: %s%n", port, e.toString());
    }
} finally {
    try {
        udpSocket.close();
    } catch (Exception e2) { }
}

Ich gebe auf für heute 😞
 
Nicht wundern - Unser Foren-Clown Tobias wird hier immer direkt gesperrt ... ich habe einmal seine Posts stehen gelassen, auch wenn er nicht wirklich was Neues beitragen konnte ...
 
Auf welchem System versuchst Du es? Ich habe es auf einem M1 Mac probiert und habe die Exception erhalten.

Mein Code:
Java:
package de.kneitzel;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;

public class UDPTest {
    public static void main(String[] args) throws Exception {
        final InetAddress address = InetAddress.getByName("127.0.0.1");
        final int port = 12345;
        final DatagramSocket udpSocket = new DatagramSocket();
        try {
            udpSocket.setSoTimeout(10000);
            udpSocket.connect(address, port); // <-- neu hinzugefügt !!!
            try {
                final byte[] message = "hello".getBytes(StandardCharsets.US_ASCII);
                udpSocket.send(new DatagramPacket(message, message.length, address, port));
                Thread.sleep(1000);
                final byte buffer[] = new byte[1024];
                udpSocket.receive(new DatagramPacket(buffer, buffer.length));
            } catch(Exception e) {
                System.err.printf("Error while trying port %d: %s%n", port, e.toString());
            }
        } finally {
            try {
                udpSocket.close();
            } catch (Exception e2) { }
        }
    }
}

Die Ausgabe:
Code:
/Users/konrad/Library/Java/JavaVirtualMachines/temurin-21.0.1/Contents/Home/bin/java -javaagent:/Users/konrad/Applications/IntelliJ IDEA Ultimate.app/Contents/lib/idea_rt.jar=61751:/Users/konrad/Applications/IntelliJ IDEA Ultimate.app/Contents/bin -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath /Users/konrad/Projects/GitHub/JavaMavenApp/target/classes:/Users/konrad/.m2/repository/org/projectlombok/lombok/1.18.30/lombok-1.18.30.jar:/Users/konrad/.m2/repository/org/jetbrains/annotations/24.1.0/annotations-24.1.0.jar:/Users/konrad/.m2/repository/net/lingala/zip4j/zip4j/1.3.2/zip4j-1.3.2.jar de.kneitzel.UDPTest
Error while trying port 12345: java.net.PortUnreachableException

Process finished with exit code 0
 
Und was ist das genaue Setup? Also auf was für einem Rechner startest Du es und was für ein System ist hinter dieser ip, die Du angegeben hast?

(Was ich nicht erwähnt habe: Das geht natürlich auch mit anderen Adressen als 127.0.0.1 - ich habe z.B. meine Fritzbox angegeben. Nur wenn man den Code kopiert, dann ist die IP der Fritzbox bei euch ungültig. Daher localhost für einfaches ausprobieren!)
 
Ich habe bei mir in der Umgebung noch etwas getestet: Ich weiss nicht genau wieso, aber bei mir sind paar Pakete verloren gegangen. Wenn ich da die Schleife drumherum mache und dann alles laufen lasse, dann kommt es zu Problemen. So war bei mir in der Regel ab dem 5ten Eintrag auch Timeouts zu beobachten.

Das habe ich aber jetzt nicht weiter verfolgt. Hier müsste man mal mitschneiden um zu sehen, was für Pakete raus gehen und ob die ICMP Pakete wirklich zurück kommen. An irgend einer Stelle geht da etwas schief, denn ich glaube nicht an so viel Verlust ...

Der Workaround bei mir war, dass ich bei einem Timeout erneut probiert habe. So war dann halt ein Timeout erst einmal kein Ergebnis, das ich akzeptiert habe.

Die Timeouts habe ich dazu dann natürlich auch runter gesetzt - 100ms reichen im lokalen Netz.

Das einfach als Abschluss ehe ich jetzt ins Bett gehe 🙂
 
Da ich es jetzt auf dem Windows Firmenrechner prüfen konnte:

Ich habe es erst mit der 127.0.0.1 probiert: Erfolgreich.
Mit meiner Fritzbox war es erst nicht erfolgreich. Das lag aber einfach an der Windows Firewall. Neue Regel erstellt:
  • Protokoll ICMPv4
  • Lokal: beliebige ip, Remote: ip der Fritzbox
  • Verbindung zulassen
==> Schon klappt es auch auf dem Windows System mit der Fritzbox
 
Okay, habe mir jetzt ein Mac-Rechner ausgeliehen, mit "brew" ein JRE nachinstalliert, und siehe da:
Code:
% sw_vers
ProductName:            macOS
ProductVersion:         14.3
BuildVersion:           23D56

% java -jar udp-tester.jar fileserver-2.local 12345 12354
Host: 192.168.2.206

Testing UDP port 12345, please wait....
Sleeping...
Waiting for response...
Error while receiving from port 12345: java.net.PortUnreachableException

Testing UDP port 12346, please wait....
Sleeping...
Waiting for response...
Error while receiving from port 12346: java.net.PortUnreachableException

Testing UDP port 12347, please wait....
Sleeping...
Waiting for response...
Error while receiving from port 12347: java.net.PortUnreachableException

...

So viel zu "Write once, run anywhere" 😂

Auch interessant: Mit send() gefolgt von einem hinreichend langem sleep() gefolgt von receive() klappt es anscheinend zuverlässig mit der PortUnreachabkeException. Mit send() direkt gefolgt von receive(), mit einem hinreichend großen "SoTimeout", klappt es hingegen nur zu 90%. Bekomme dann immer noch ab und zu eine SocketTimeoutException. Da scheint es also irgendwo eine Race-Condition zu geben...
 
Zuletzt bearbeitet:
Ich bin mir sicher, dass es auch unter Windows und Linux funktionieren sollte. Windows habe ich ja auch testen können. Linux habe ich derzeit kein System zur Hand, auf dem ich testen könnte (evtl. mache ich es auf einem Node meines kubernetes clusters ... aber da ein Java installieren nur für so einen Test möchte ich nicht wirklich machen).

Daher die Frage nach dem genauen Aufbau. Denn ich würde tatsächlich vermuten, dass die Pakete doch irgendwo in einer Firewall gelandet sind. Hast Du es mal mit 127.0.0.1 getestet, wo es sonst nicht ging? Das wird in der Regel nicht mit einer Firewall blockiert.
 

Neue Themen


Zurück
Oben