Comment éviter une exception NoRouteToHostException?

Divulgation: le code sur lequel je travaille concerne les cours universitaires.

Contexte: La tâche que j’essaie de mener à bien consiste à signaler l’effet de différentes techniques de threading. Pour ce faire, j’ai écrit plusieurs classes qui répondent à une demande d’un client utilisant Java Sockets. L’idée est d’inonder le serveur de requêtes et de décrire comment différentes stratégies de threading peuvent y faire face. Chaque client effectuera 100 demandes et à chaque itération, nous augmentons le nombre de clients de 50 jusqu’à ce que quelque chose se brise.

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

 Causé par: java.net.NoRouteToHostException: impossible d'atsortingbuer l'adresse demandée
     at java.net.PlainSocketImpl.socketConnect (méthode native)
     sur java.net.PlainSocketImpl.doConnect (PlainSocketImpl.java:333)

Cela se produit dans plusieurs scénarios, notamment lorsque le client et le serveur sont exécutés sur localhost. Les connexions peuvent être établies avec succès pendant un certain temps, après avoir tenté de connecter 150 clients que l’exception est déclenchée.

Ma première pensée a été que cela pourrait être la limite de Linux sur les descripteurs de fichiers ouverts (1024) mais je ne le pense pas. J’ai également vérifié que toutes les connexions entre les sockets étaient correctement fermées (c’est-à-dire dans un bloc finally correct).

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

Est-ce que quelqu’un à déjà rencontré cela avant? Comment puis-je éviter l’exception NoRouteToHostException?


EDIT (d’autres questions sont en italique)

Quelques bonnes réponses à ce jour qui indiquent soit la gamme Ephemeral Port Range ou RFC 2780. Les deux suggèrent que j’ai trop de connexions ouvertes. Dans les deux cas, il semble que le nombre de connexions à effectuer pour atteindre cette limite suggère que, à un moment donné, je ne ferme pas les connexions.

Après avoir débogué à la fois le client et le serveur, les deux utilisateurs ont été frappés par la méthode appelée myJava-Net-SocketInstance.close() . Cela suggère que les connexions sont fermées (du moins dans les cas non exceptionnels). Est-ce une suggestion correcte?

En outre, y a-t-il une attente au niveau du système d’exploitation requirejse pour que les ports redeviennent disponibles? Il serait possible d’exécuter le programme à une heure différente pour chaque 50+ clients si cela nécessitait une courte période (ou une exécution optimiste, avant d’exécuter la prochaine tentative).


EDITER v2.0

Ayant pris les 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 souhaité et je suis toujours limité à 250-300 clients. Une fois le programme terminé, l’exécution de la commande netstat -a indique qu’il y a beaucoup de connexions socket dans l’état TIME_WAIT.

Ma supposition était que si un socket était dans l’état TIME-WAIT et avait été défini avec l’option SO-REUSEADDR , tous les nouveaux sockets essayant d’utiliser ce port seraient en mesure – cependant, je reçois toujours l’exception NoRouteToHostException.

Est-ce correct? Y a-t-il autre chose qui puisse être fait pour résoudre ce problème?

Avez-vous essayé le réglage:

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

et / ou

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

Ces parameters peuvent obliger Linux à réutiliser les sockets TIME_WAIT. Malheureusement, je ne trouve aucune documentation définitive.

Cela peut aider:

La chaîne portuaire éphémère

Une autre ramification importante de la plage de ports éphémères est qu’elle limite le nombre maximum de connexions d’une machine à un service spécifique sur une machine distante! Le protocole TCP / IP utilise le 4-tuple de la connexion pour distinguer les connexions. Par conséquent, si la plage de ports éphémères n’est que de 4 000 ports, cela signifie qu’il ne peut y avoir que 4 000 connexions uniques entre un ordinateur client et un service distant.

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’aurais 28 232 ports pour les connexions client. Par conséquent, votre test échouera dès que vous aurez plus de 280 clients.

Impossible d’atsortingbuer l’adresse demandée est la chaîne d’erreur pour l’erreur EADDRNOTAVAIL.

Je pense que vous êtes à court de ports source. Il existe 16 383 sockets dans la plage dynamic disponibles pour une utilisation en tant que port source (voir RFC 2780 ). 150 clients * 100 connexions = 15 000 ports – vous atteignez donc probablement cette limite.

Si vous manquez de ports source mais que vous ne gérez pas réellement de nombreuses connexions ouvertes, définissez l’option de socket SO_REUSEADDR . Cela vous permettra de réutiliser les ports locaux qui sont toujours dans l’état TIME_WAIT .

Si vous fermez 500 connexions par seconde, vous serez à court de sockets. Si vous vous connectez aux mêmes emplacements (serveurs Web) qui utilisent keepalive, vous pouvez implémenter des pools de connexions afin de ne pas fermer ni rouvrir les sockets.

Cela permettra également de sauver cpu.

L’utilisation de tcp_tw_recycle et de tcp_tw_reuse peut entraîner l’arrivée de paquets provenant de la connexion précédente, c’est pourquoi il faut attendre 1 minute avant que les paquets disparaissent.

Pour tous les autres utilisateurs Java qui se heurtent à cette question, je recommande d’utiliser le regroupement de connexions afin que les connexions soient réutilisées correctement.