Lors de l'ouverture d'un socket sur IP: 0.0.0.0
et Port: 37845
(juste un port fermé aléatoire) avec la classe de socket de java, le socket se connecte échoue avec une java.net.NoRouteToHostException
sur Machine 1
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("0.0.0.0", 37845))
J'utilise ce testcode: p >
[qa@localhost ~]$ cat /etc/centos-release CentOS Linux release 7.6.1810 (Core) [qa@localhost ~]$ java -version openjdk version "1.8.0_191" OpenJDK Runtime Environment (build 1.8.0_191-b12) OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode) [qa@localhost ~]$ uname -a Linux localhost.localdomain 3.10.0-957.1.3.el7.x86_64 #1 SMP Thu Nov 29 14:49:43 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
Ce que j'attends en fait est une java.net.ConnectException: Connexion refusée (Connexion refusée)
, qui c'est aussi ce que j'obtiens avec une autre machine Cent OS, appelons-la Machine2
[qa@jenkins-staging ~]$ cat /etc/centos-release CentOS Linux release 7.6.1810 (Core) [qa@jenkins-staging ~]$ java -version openjdk version "1.8.0_191" OpenJDK Runtime Environment (build 1.8.0_191-b12) OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode) [qa@jenkins-staging ~]$ uname -a Linux jenkins-staging.fancydomain 3.10.0-514.el7.x86_64 #1 SMP Tue Nov 22 16:42:41 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
Machine1:
Exception in thread "main" java.net.ConnectException: Connection refused (Connection refused) at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:204) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at Test.main(Test.java:26)
Machine2:
import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; public class Test { public static void main(String[] args) throws Exception { Socket socket; // create a socket with a timeout SocketAddress socketAddress = new InetSocketAddress("0.0.0.0", 37845); // create a socket socket = new Socket(); // this method will block no more than timeout ms. int timeoutInMs = 10 * 1000; // 10 seconds socket.connect(socketAddress, timeoutInMs); System.err.println("SUCCESS"); } }
Il semble donc la seule différence est la version du noyau.
J'ai essayé le "même" code avec python, là j'obtiens toujours un
ConnectionRefused
(sur Machine1 + Machine2 )
Exception in thread "main" java.net.NoRouteToHostException: No route to host (Host unreachable) at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:204) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at Test.main(Test.java:26)
127.0.0.1
0.0.0.0
par 127.0.0.1
dans le code source résout le
problème, et ConnectionRefused
(attendu) est déclenché au lieu de NoRouteToHostException
Dans l'exemple ci-dessus, j'ai utilisé un port qui est fermé, juste à des fins de démonstration. La même chose s'applique s'il y a un port d'écoute réel sur la machine, alors ce sera ConnectionRefused
vs SUCCESS
3 Réponses :
0.0.0.0
est une adresse spéciale , qui fait partie de la plage spéciale 0.0.0.0/8
qui signifie "réseau actuel" ou "non spécifié". Vous ne pouvez pas vous y connecter car il n'est pas défini comme destination.
C'est pourquoi vous obtenez une NoRouteToHostException
- l'adresse n'est tout simplement pas routable. Vous obtiendrez un échec similaire si vous essayez d'exécuter ping 0.0.0.0
ou une commande similaire.
ConnectionRefused
se produit lorsque la machine distante refuse réellement la connexion, ce qui est généralement un signe que la machine distante n'a pas de socket d'écoute ou se trouve derrière un pare-feu.
unix.stackexchange.com/a/419881 Cette réponse explique qu'en pratique vous pouvez la spécifier comme destination, mais évidemment comme OP a constaté que cela ne fonctionne pas toujours comme prévu.
Voici la documentation des erreurs de socket Java ce qui explique aussi la différence entre eux
@MarkReedZ Je n'ai jamais rien vu de tel dans la pratique, et malheureusement la réponse que vous avez citée ne fournit aucun exemple de ce qui se passe. AFAIK, 0.0.0.0
ne peut être utilisé que comme adresse source lors de la liaison d'un socket. Cela n'a absolument aucun sens en tant que destination. Si cela fonctionne sur une plate-forme, je le considérerais comme un bogue.
En fait, ce n'est pas vrai, veuillez consulter la section "Autres choses que j'ai essayées". Je mentionne que le ping 0.0.0.0
fonctionne. [qa @ jenkins-staging ~] $ ping 0.0.0.0 PING 0.0.0.0 (127.0.0.1) 56 (84) octets de données. 64 octets à partir de 127.0.0.1: icmp_seq = 1 ttl = 64 temps = 0,255 ms 64 octets à partir de 127.0.0.1: icmp_seq = 2 ttl = 64 temps = 0,113 ms ^ C --- 0.0.0.0 statistiques de ping --- 4 paquets transmis , 4 reçus, 0% de perte de paquets, temps 3000ms rtt min / moy / max / mdev = 0.113 / 0.149 / 0.255 / 0.062 ms
@Malt J'ai vu cela en pratique car il est utilisé dans le plugin docker pour jenkins, c'est ainsi que je suis tombé sur ce bug / comportement en premier lieu. Le plugin ne fonctionnait pas pour mes jenkins bien qu'un autre jenkins fonctionnait avec la même configuration. J'ai fait du débogage et c'est ainsi que j'ai découvert cela en premier lieu. Vous pouvez également essayer de vous connecter à 0.0.0.0 dans Chrome sur Ubuntu, bien que cela ne fonctionne pas dans Windows 10 Chrome.
Je voudrais certainement installer Wireshark sur les deux machines et comparer tous les scénarios.
Plus précisément:
https://superuser.com/questions/720851/connection-refused -vs-no-route-to-host
"Connexion refusée" signifie que la machine cible a activement rejeté la connexion ... l'une des raisons suivantes est probablement la raison:
- Rien n’écoute sur le port
- Le pare-feu bloque la connexion avec REJECT
Le message ICMP, "pas de route vers l'hôte", signifie que ARP ne peut pas trouver le Adresse de couche 2 pour l'hôte de destination. Habituellement, cela signifie que que l'hôte avec cette adresse IP n'est pas en ligne ou ne répond pas.
Bien sûr, cela soulève la question de savoir pourquoi Python se comporte d'une manière et Java d'une manière différente ... sur la même machine.
Encore une fois, je vous encourage à regarder Wireshark. En particulier, regardez 1) la négociation TCP à trois voies, et 2) l'appel ARP qui le précède.
PS: Comme le malt dit ci-dessus:
0.0.0.0 ... l'adresse n'est tout simplement pas routable.
Sous Windows, vous pouvez obtenir WSAEADDRNOTAVAIL -L'adresse distante n'est pas une adresse valide
Ce qui soulève la question de savoir pourquoi vous obtenez "ConnectionRefused".
Encore une fois, je suis vraiment curieux de savoir ce que Wireshark vous montre.
Pour une destination non routable, WireShark ne doit afficher aucun paquet. La pile TCP / IP du système d'exploitation doit renvoyer une erreur avant d'envoyer quoi que ce soit.
Merci pour votre réponse. En ce qui concerne le traçage du trafic, j'ai fait un tcpdump pour les requêtes arp mais même pas 1 requête arp n'est envoyée / reçue. En ce qui concerne le traçage de la poignée de main TCP, comme Malt l'a mentionné, cela n'a pas de sens car avec NoRouteToHostException
il n'y aura même pas de paquet TCP SYN car il échoue avant cela.
J'ai intégré le code que vous avez fourni et l'ai exécuté sur le système Windows 10, j'obtiens l'exception correcte
Exception in thread "main" java.net.ConnectException: Connection refused: connect at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:204) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at Main.main(Main.java:8) Process finished with exit code 1Oracle JDK 8.0.202
import java.net.InetSocketAddress; import java.net.Socket; public class Main { public static void main(String[] args) throws Exception { new Socket().connect(new InetSocketAddress("0.0.0.0", 37845), 10_0000); } }
C'est intéressant
Je ne sais pas pourquoi vous testez ça. C'est invalide de toute façon.
@ user207421 à l'origine à cause de ceci: github.com/jenkinsci/docker-plugin/pull/720 , mais pour le moment, cela me dérange simplement que les deux machines se comportent différemment et je ne peux pas dire pourquoi.