59 votes

Comment éviter une NoRouteToHostException ?

Divulgation : le code sur lequel je travaille est destiné à un cours universitaire.

Historique : La tâche que j'essaie d'accomplir est de rendre compte de l'effet de différentes techniques de threading. Pour ce faire, j'ai écrit plusieurs classes qui répondent à une requête d'un client en utilisant des Java Sockets. L'idée est d'inonder le serveur de requêtes et d'étudier comment les différentes stratégies de threading y font face. Chaque client fera 100 demandes, et à chaque itération, nous augmentons le nombre de clients de 50 jusqu'à ce que quelque chose se casse.

Problème : de manière répétée et constante, une exception se produit :

Caused by: java.net.NoRouteToHostException: Cannot assign requested address
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)

Cela se produit dans plusieurs scénarios, notamment lorsque le client et le serveur fonctionnent tous deux sur localhost. Les connexions peuvent être établies avec succès pendant un certain temps, mais c'est peu après avoir essayé de connecter 150 clients que l'exception est levée.

J'ai d'abord pensé qu'il pouvait s'agir de la limite imposée par Linux aux descripteurs de fichiers ouverts (1024), mais je ne le pense pas. J'ai également vérifié que toutes les connexions entre les sockets sont fermées correctement (c'est-à-dire dans un délai correct d'un an). finally bloc).

J'hésite à poster le code parce que je ne suis pas sûr des parties qui seraient les plus pertinentes, et je ne veux pas avoir une énorme liste de code dans la question.

Quelqu'un a-t-il déjà rencontré ce problème ? Comment puis-je éviter l'exception NoRouteToHostException ?


EDIT (les autres questions sont en italique)

Quelques bonnes réponses jusqu'à présent qui pointent vers la gamme de ports éphémères ou la RFC 2780. Les deux suggèrent que j'ai trop de connexions ouvertes. Dans les deux cas, il semble que le nombre de connexions nécessaires pour atteindre cette limite suggère qu'à un moment donné, je ne ferme pas les connexions.

Après avoir débogué à la fois le client et le serveur, on a constaté qu'ils utilisent tous deux l'appel de méthode myJava-Net-SocketInstance.close() . Cela suggère que les connexions sont fermées (au moins dans le cas non exceptionnel). Cette suggestion est-elle correcte ?

Aussi, Y a-t-il une attente au niveau du système d'exploitation pour que les ports soient à nouveau disponibles ? Il serait possible d'exécuter le programme une fois séparée pour chaque 50+ clients si cela ne nécessitait qu'une courte période (ou de manière optimiste, l'exécution d'une commande) avant d'exécuter la prochaine tentative.


EDIT v2.0

Ayant pris connaissance des bonnes réponses fournies, j'ai modifié mon code pour utiliser la méthode setReuseAddress(true) avec chaque connexion Socket effectuée sur le client. Cela n'a pas eu l'effet escompté, et je suis toujours limité à 250-300 clients. Après la fin du programme, l'exécution de la commande netstat -a montre qu'il y a beaucoup de connexions de socket dans l'état TIME_WAIT.

Je supposais que si une prise se trouvait dans la section TIME-WAIT et avait été fixé avec le SO-REUSEADDR tous les nouveaux sockets qui tentent d'utiliser ce port pourront le faire. Cependant, je reçois toujours l'exception NoRouteToHostException.

Est-ce correct ? Y a-t-il autre chose à faire pour résoudre ce problème ?

52voto

atomice Points 2273

Avez-vous essayé de régler :

echo "1" >/proc/sys/net/ipv4/tcp_tw_reuse

et/ou

echo "1" >/proc/sys/net/ipv4/tcp_tw_recycle

Ces paramètres peuvent amener Linux à réutiliser les sockets TIME_WAIT. Malheureusement, je ne peux pas trouver de documentation définitive.

16voto

sfussenegger Points 16204

Cela peut aider :

La gamme des ports éphémères

Une autre ramification importante de la la plage de ports éphémères est qu'elle limite le nombre maximal de connexions d'une une machine à un service spécifique sur une machine distante ! Le protocole TCP/IP utilise le 4-uplet de la connexion pour distinguer les connexions, donc si la plage de ports éphémères n'est que de 4000 ports, cela signifie qu'il ne peut y avoir qu'il ne peut y avoir que 4000 connexions uniques d'un machine cliente à un service distant à à un moment donné.

Alors peut-être que vous êtes à court de ports disponibles. Pour obtenir le nombre de ports disponibles, voir

$ cat /proc/sys/net/ipv4/ip_local_port_range 
32768   61000

La sortie provient de mon système Ubuntu, où j'ai 28 232 ports pour les connexions clients. Par conséquent, votre test échouera dès que vous aurez 280+ clients.

9voto

atomice Points 2273

Cannot assign requested address est la chaîne d'erreur pour l'erreur EADDRNOTAVAIL.

Je pense que vous êtes à court de ports sources. Il y a 16 383 sockets dans la gamme dynamique disponibles pour être utilisés comme port source (cf. RFC 2780 ). 150 clients * 100 connexions = 15 000 ports - vous atteignez donc probablement cette limite.

5voto

David Joyner Points 4994

Si vous êtes à court de ports sources mais que vous ne maintenez pas un grand nombre de connexions ouvertes, définissez la valeur de l'attribut SO_REUSEADDR option de prise de courant. Cela vous permettra de réutiliser les ports locaux qui sont toujours dans la base de données de TIME_WAIT l'État.

0voto

Bryan Larson Points 73

Pour tous les autres utilisateurs de Java qui tomberaient sur cette question, je recommanderais d'utiliser la mise en commun des connexions c3p0 afin que les connexions soient réutilisées correctement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X