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? :rolleyes:

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:

LimDul

Top Contributor
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.
 

KonradN

Super-Moderator
Mitarbeiter
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.
 

JavaDevOp

Mitglied
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:

Jw456

Top Contributor
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.
 

KonradN

Super-Moderator
Mitarbeiter
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.
 

JavaDevOp

Mitglied
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:

KonradN

Super-Moderator
Mitarbeiter
Klingt interessant. Aber wie mache ich das mit Java am besten? o_O
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.
 

JavaDevOp

Mitglied
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". :D
 
Zuletzt bearbeitet:

Dukel

Top Contributor
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?
 

KonradN

Super-Moderator
Mitarbeiter
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.
 

JavaDevOp

Mitglied
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 😢
 

KonradN

Super-Moderator
Mitarbeiter
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.
 

JavaDevOp

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

KonradN

Super-Moderator
Mitarbeiter
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.
 

JavaDevOp

Mitglied
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...
 

JavaDevOp

Mitglied
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 😞
 

KonradN

Super-Moderator
Mitarbeiter
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 ...
 

KonradN

Super-Moderator
Mitarbeiter
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
 

KonradN

Super-Moderator
Mitarbeiter
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!)
 

KonradN

Super-Moderator
Mitarbeiter
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 :)
 

KonradN

Super-Moderator
Mitarbeiter
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
 

JavaDevOp

Mitglied
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:

KonradN

Super-Moderator
Mitarbeiter
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.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
FrankenDerStein Socket UDP Multithreading für ein Port Netzwerkprogrammierung 2
T multithreaded multiport socketListener beendet TCP-Port-Listening Netzwerkprogrammierung 16
C Proxy Server - Antwort auf welchem Port Netzwerkprogrammierung 1
precoc Port Listener Netzwerkprogrammierung 2
T Port forwarding Netzwerkprogrammierung 11
Rudolf Socket An welchen Port sendet ein Mailserver zu einem anderen Mailserver Netzwerkprogrammierung 8
C Socket Connection refused bei Internetverbindung - Welcher Port? Netzwerkprogrammierung 5
S Port abhören Netzwerkprogrammierung 11
M Gleicher Port für Senden und Empfangen ? Netzwerkprogrammierung 17
Dit_ UDP Port testen | Ping Google? Netzwerkprogrammierung 7
J Port lauschen Netzwerkprogrammierung 2
D Weiterer Thread auf Port 843 horcht Netzwerkprogrammierung 7
H Mysql port forwarding Netzwerkprogrammierung 5
Dit_ UDP Port bestimmen | Windows, MAC, Linux... Netzwerkprogrammierung 2
J UDP port packete lesen,wenn dieser besetzt ist Netzwerkprogrammierung 3
T Java Mail port ändern Netzwerkprogrammierung 4
1 Socket Immer offener Port? Netzwerkprogrammierung 11
R wie prüfe ich ob ein port frei is ? Netzwerkprogrammierung 7
S Port auf einer bestimmten IP-Adresse auslesen? Netzwerkprogrammierung 6
X Port scannen/schicken Netzwerkprogrammierung 4
W scan remote UDP port Netzwerkprogrammierung 6
M Socket Herausfinden ob server auf port läuft Netzwerkprogrammierung 8
F UDP Receive und Send am gleichen Port Netzwerkprogrammierung 3
G Port freigeben Netzwerkprogrammierung 3
P Sockets +Port Forwarding = Chaos Netzwerkprogrammierung 4
J GSM Modem an Serial Port ansteuern (AT commands) Netzwerkprogrammierung 2
T Server ohne Port Netzwerkprogrammierung 4
Schandro Herausfinden ob hinter einem Port bereits ein ServerSocket steckt Netzwerkprogrammierung 2
ABstraCT Applet multipler port Zugriff möglich ? Netzwerkprogrammierung 5
ABstraCT Telnet port Zugriff problem (public IP) Netzwerkprogrammierung 12
T ohne Port Freigabe. Netzwerkprogrammierung 6
K Problem mit Com-Port-Komunikation Netzwerkprogrammierung 57
G "Port already in use" RMI über SSL Netzwerkprogrammierung 9
S port lauschen Netzwerkprogrammierung 2
feuervogel Sockets - Lokalen Port aber nicht IP bestimmen Netzwerkprogrammierung 3
G port scanner Netzwerkprogrammierung 6
S Port mithören Netzwerkprogrammierung 9
P jakarta.HttpClient: Port bei GetMethod angeben Netzwerkprogrammierung 3
A port noch belegt Netzwerkprogrammierung 3
K Port 13 nur einmal abfragbar? Netzwerkprogrammierung 2
R Problem mit mehreren Anfragen auf demselben Port Netzwerkprogrammierung 2
TRunKX Ein Port mehrere Verbindungen? Netzwerkprogrammierung 7
H Port abhören Netzwerkprogrammierung 3
F freien Port finden Netzwerkprogrammierung 7
S GEHT DAS? - Nur eine Frage! (Printer Port direkt ansteuern?) Netzwerkprogrammierung 4
T Kann man jeden Port für Programm verwenden? Netzwerkprogrammierung 2
T PORT 80 überwachen Netzwerkprogrammierung 12
G an port lauschen Netzwerkprogrammierung 10
K nicht physikalische com port ansprechen ? Netzwerkprogrammierung 3
S SSLSocketFactory.createSocket(String hostname, int port),wo? Netzwerkprogrammierung 5
G Port belegt nach Server restart Netzwerkprogrammierung 5
R Port trotz aktiver Firewall nutzen ! Netzwerkprogrammierung 9
D Zustand prüfen trotz Loadbalancer Netzwerkprogrammierung 3
F TCP Socket auf Verbindungsabbruch prüfen Netzwerkprogrammierung 15
J Prüfen, ob remote UDT Server erreichbar ist Netzwerkprogrammierung 0
Dit_ UDP Pakete prüfen, sortieren Netzwerkprogrammierung 20
J Socket ObjectInputStream prüfen Netzwerkprogrammierung 8
G Verbindungsstatus prüfen Netzwerkprogrammierung 4
J Prüfen ob Befehl ausgeführt wurde moeglich? Netzwerkprogrammierung 15
hdi Webseite auf Download-Links prüfen und Download starten? Netzwerkprogrammierung 7
S Prüfen ob IP aus definiertem Subnetz Netzwerkprogrammierung 4
M [Commons NET] Prüfen, ob auf FTP Datei vorhanden ist Netzwerkprogrammierung 2
J Prüfen, ob IP-Adresse gültig ist Netzwerkprogrammierung 5
K Mit Java-MailAPI dir Verfügbarkeit eines SMTP-Servers prüfen Netzwerkprogrammierung 4
C Verbindung zum Server prüfen mit einem vorhandenem Socket Netzwerkprogrammierung 4
B Internetverbindung prüfen unter Windows Netzwerkprogrammierung 1
B Internetverbinding prüfen Netzwerkprogrammierung 2
P mit javamail gmx postfach prüfen Netzwerkprogrammierung 8

Ähnliche Java Themen

Neue Themen


Oben