Der obige Code wird kompiliert, um auf einer Linux-Maschine zu laufen.
Nehmen Sie an, dass der obige Code Daten an eine Maschine mit der IP-Adresse 128.88.143.113
sendet. Kein UDP-Socket ist an den Port 9090
at 128.88.143.113
gebunden.
In der Schleife while
ist der erste Aufruf von send()
erfolgreich (das Paket geht tatsächlich auf den Draht; es wurde mit trace
überprüft) und der zweite send()
schlägt mit Connection refused
fehl. Die third send()
ist erfolgreich und die vierte fehlschlägt und so weiter.
Ich vermute, dass nach dem ersten send()
der Stack eine ICMP-Fehlermeldung (in tcpdump
auf dem Linux-Rechner gesehen) erhält, die in der Socket-Struktur gespeichert ist. Das zweite send()
schlägt fehl, wenn dieser Fehler erkannt wird und kein Paket tatsächlich gesendet wird. Die zweite send()
löscht auch den Fehler in der Socket-Struktur. Daher ist die dritte send()
erfolgreich und die vierte fehlschlägt und so weiter.
Fragen:
send()
erfolgreich sein? Nach der Linux-man-Seite für udp :
Alle schwerwiegenden Fehler werden an die Benutzer als Fehler zurückgeben, auch wenn die Steckdose ist nicht verbunden. Das beinhaltet asynchrone Fehler, die von der Netzwerk. Sie erhalten möglicherweise einen Fehler für eine früheres Paket, das auf dem gesendet wurde gleiche Steckdose. Dieses Verhalten ist unterschiedlich von vielen anderen BSD-Sockets Implementierungen, die keine bestehen Fehler, außer der Socket ist verbunden. Linux Verhalten von RFC 1122 beauftragt wird.
Insbesondere das RFC (4.1.3.3) heißt es:
UDP MUSS alle ICMP-Fehler an die Anwendungsebene weitergeben Nachrichten, die es von der IP-Schicht erhält. Konzeptionell zumindest kann dies mit einem Upcall zu den erreicht werden ERROR_REPORT-Routine
Ihre Hypothese ist richtig. Die Linux-UDP (7) -Mantseite beschreibt die Situation so:
Alle schwerwiegenden Fehler werden übergeben an den Benutzer als Fehler zurückgeben sogar wenn der Sockel nicht angeschlossen ist. Dies schließt asynchrone Fehler ein aus dem Netzwerk erhalten. Du darfst Erhalte einen Fehler für ein früheres Paket das wurde an derselben Buchse gesendet.
Dieses Verhalten unterscheidet sich von vielen anderen BSD-Socket-Implementierungen, die dies nicht tun Übergeben Sie alle Fehler, es sei denn, der Socket ist in Verbindung gebracht. Das Verhalten von Linux ist Mandat von RFC 1122 .Wenn die Option
IP_RECVERR
ist aktiviert alle Fehler sind in der gespeichert Socket-Fehlerwarteschlange und kann empfangen werden vonrecvmsg(2)
mit derMSG_ERRQUEUE
flag gesetzt.
Es wäre interessant, den entsprechenden Code mit sendto()
anstatt mit connect()
und send()
zu vergleichen.
Fällt der angezeigte Code auf die gleiche Weise aus, wenn Sie zwischen den einzelnen Sendevorgängen einen bestimmten Zeitraum belassen, dh, dass der ICMP-Fehlerzustand für eine gewisse Zeit im Socket verbleibt oder der zweite send()
weiterhin fehlschlägt? Wenn du es verlassen hast, sagen wir, eine Stunde?
Ich erwarte, dass Ihre Annahme richtig ist, der Netzwerkstapel versucht, clever zu sein. Es gibt keinen anderen Punkt, an dem die Verbindung zurückgewiesen werden könnte, da beim Senden des connect()
-Aufrufs nichts gesendet wird. Sie speichert einfach die angegebene Adresse, so dass der Socket "logisch" verbunden ist und Aufrufe von send()
dann funktionieren können / p>
Ich hatte das gleiche Problem; und das liegt daran, dass die udp-Nachrichtenwarteschlange gefüllt ist, wenn niemand zuhört und die Warteschlange löscht.